diff --git a/README.md b/README.md
index a65dc77..d759dac 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
该项目包括了一个小说网站代理和一个独立的小说弹幕网站,包括小说在线阅读、TXT下载、小说弹幕、小说自动爬取、小说内容自动分享到微博、链接自动推送到百度搜索引擎等功能。现公布web端代码,需要移动端和小程序代码的也可以找我。
#### 软件架构
-Springboot+mybatis+Mysql+Ehcache
+Springboot+mybatis+Mysql+Ehcache+Layui
#### 安装教程
diff --git a/books.ndm b/books.ndm
new file mode 100644
index 0000000..02db6a8
Binary files /dev/null and b/books.ndm differ
diff --git a/books_v2.ndm b/books_v2.ndm
new file mode 100644
index 0000000..700bc2c
Binary files /dev/null and b/books_v2.ndm differ
diff --git a/books_v3.ndm b/books_v3.ndm
new file mode 100644
index 0000000..79a131a
Binary files /dev/null and b/books_v3.ndm differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..12a3fe7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,113 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.1.RELEASE
+
+
+ xyz.zinglizingli
+ search
+ 0.0.1-SNAPSHOT
+ search
+ 搜索引擎
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ net.sf.ehcache
+ ehcache
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ 1.2.5
+
+
+ com.cuisongliu
+ orderbyhelper-spring-boot-starter
+ 1.0.2
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.11
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 1.3.2
+
+
+
+
+
+ org.apache.httpcomponents
+ httpcore
+ 4.4.10
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.6
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+ alimaven
+ aliyun maven
+ http://maven.aliyun.com/nexus/content/groups/public/
+
+
+
+
+
+
diff --git a/runSearchJava.sh b/runSearchJava.sh
new file mode 100644
index 0000000..a8039c2
--- /dev/null
+++ b/runSearchJava.sh
@@ -0,0 +1,2 @@
+setsid java -jar -Dserver.port=8080 -Dbrowser.cookie="SINAGLOBAL=5945695441587.724.1559298271897; __guid=109181959.2094437407894937900.1565875017257.2095; un=13560421324; _s_tentry=-; Apache=8157572449986.1455.1566918991846; ULV=1566918991855:7:6:1:8157572449986.1455.1566918991846:1566086532731; login_sid_t=0cc80b9f5ea5f473e83fce3054291c03; cross_origin_proto=SSL; un=13560421324; YF-Widget-G0=4aade6ec367f09ec0a5eec921227137f; WBtopGlobal_register_version=307744aa77dd5677; SSOLoginState=1566928337; wvr=6; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WFRg9065OjUyD0aaGsKRxPW5JpX5KMhUgL.Fo-f1hB7SKMp1h52dJLoI0qLxK-L1KqL1-eLxKMLB.-L122LxKMLB.-L122LxK-LBo5L12qLxKnLB-qLBoBLxKMLB.BL1K2t; ALF=1598668299; SCF=AsBEGOtiUG1hPLyZCxI1FunZd9Hg9hWWkgyzcAZjG6AxG74hLk9rofaMoHwpFHFbRkgXJHKRhZp9zaMBBunBaKY.; SUB=_2A25wbPrdDeRhGeNL41YR9SnNwzyIHXVTGGsVrDV8PUNbmtANLXbAkW9NSM603pUp_xGzlKh9nLI6ZnBMRUpaP35e; SUHB=0V5VPdN2jI6D4n; monitor_count=1; UOR=,,book.zinglizingli.xyz; webim_unReadCount=%7B%22time%22%3A1567132442878%2C%22dm_pub_total%22%3A0%2C%22chat_group_client%22%3A0%2C%22allcountNum%22%3A10%2C%22msgbox%22%3A0%7D" search-0.0.1-SNAPSHOT.jar
+
diff --git a/src/main/java/xyz/zinglizingli/SearchApplication.java b/src/main/java/xyz/zinglizingli/SearchApplication.java
new file mode 100644
index 0000000..9a2d49f
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/SearchApplication.java
@@ -0,0 +1,36 @@
+package xyz.zinglizingli;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+import java.io.UnsupportedEncodingException;
+
+@SpringBootApplication
+@EnableCaching
+@EnableScheduling
+@MapperScan({"xyz.zinglizingli.*.mapper"})
+public class SearchApplication {
+
+ public static void main(String[] args) {
+
+
+ SpringApplication.run(SearchApplication.class, args);
+ }
+
+ /**
+ * 解决同一时间只能一个定时任务执行的问题
+ * */
+ @Bean
+ public TaskScheduler taskScheduler() {
+ ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
+ taskScheduler.setPoolSize(5);
+ return taskScheduler;
+ }
+
+}
diff --git a/src/main/java/xyz/zinglizingli/books/constant/CacheKeyConstans.java b/src/main/java/xyz/zinglizingli/books/constant/CacheKeyConstans.java
new file mode 100644
index 0000000..ffbf214
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/constant/CacheKeyConstans.java
@@ -0,0 +1,8 @@
+package xyz.zinglizingli.books.constant;
+
+public class CacheKeyConstans {
+ public static final String HOT_BOOK_LIST_KEY = "hotBookListKey";
+ public static final String NEWST_BOOK_LIST_KEY = "newstBookListKey";
+ public static final String BOOK_CONTENT_KEY_PREFIX = "bookContentKeyPrefix";
+ public static final String EMAIL_URL_PREFIX_KEY = "emailUrlPrefixKey";
+}
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/BookContentMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/BookContentMapper.java
new file mode 100644
index 0000000..f389b28
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/BookContentMapper.java
@@ -0,0 +1,33 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.BookContent;
+import xyz.zinglizingli.books.po.BookContentExample;
+
+import java.util.List;
+
+public interface BookContentMapper {
+ int countByExample(BookContentExample example);
+
+ int deleteByExample(BookContentExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(BookContent record);
+
+ int insertSelective(BookContent record);
+
+ List selectByExample(BookContentExample example);
+
+ BookContent selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") BookContent record, @Param("example") BookContentExample example);
+
+ int updateByExample(@Param("record") BookContent record, @Param("example") BookContentExample example);
+
+ int updateByPrimaryKeySelective(BookContent record);
+
+ int updateByPrimaryKey(BookContent record);
+
+ void insertBatch(List bookContent);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/BookIndexMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/BookIndexMapper.java
new file mode 100644
index 0000000..46106f1
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/BookIndexMapper.java
@@ -0,0 +1,35 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.BookIndex;
+import xyz.zinglizingli.books.po.BookIndexExample;
+
+import java.util.List;
+
+public interface BookIndexMapper {
+ int countByExample(BookIndexExample example);
+
+ int deleteByExample(BookIndexExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(BookIndex record);
+
+ int insertSelective(BookIndex record);
+
+ List selectByExample(BookIndexExample example);
+
+ BookIndex selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") BookIndex record, @Param("example") BookIndexExample example);
+
+ int updateByExample(@Param("record") BookIndex record, @Param("example") BookIndexExample example);
+
+ int updateByPrimaryKeySelective(BookIndex record);
+
+ int updateByPrimaryKey(BookIndex record);
+
+ void insertBatch(List bookIndex);
+
+ String queryNewstIndexName(@Param("bookId") Long bookId);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/BookMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/BookMapper.java
new file mode 100644
index 0000000..3466a17
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/BookMapper.java
@@ -0,0 +1,44 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.po.BookExample;
+
+import java.util.List;
+import java.util.Set;
+
+public interface BookMapper {
+ int countByExample(BookExample example);
+
+ int deleteByExample(BookExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(Book record);
+
+ int insertSelective(Book record);
+
+ List selectByExample(BookExample example);
+
+ Book selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") Book record, @Param("example") BookExample example);
+
+ int updateByExample(@Param("record") Book record, @Param("example") BookExample example);
+
+ int updateByPrimaryKeySelective(Book record);
+
+ int updateByPrimaryKey(Book record);
+
+ List search(@Param("userId") String userId, @Param("ids") String ids, @Param("keyword") String keyword, @Param("catId") Integer catId, @Param("softCat") Integer softCat,@Param("softTag") String softTag, @Param("bookStatus") String bookStatus);
+
+ void addVisitCount(@Param("bookId") Long bookId);
+
+ Book queryRandomBook();
+
+ Book queryNewstBook(Set sendIds);
+
+ List queryNewstBookIdList();
+
+ List queryEndBookIdList();
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/CategoryMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/CategoryMapper.java
new file mode 100644
index 0000000..1a72f1b
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/CategoryMapper.java
@@ -0,0 +1,31 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.Category;
+import xyz.zinglizingli.books.po.CategoryExample;
+
+import java.util.List;
+
+public interface CategoryMapper {
+ int countByExample(CategoryExample example);
+
+ int deleteByExample(CategoryExample example);
+
+ int deleteByPrimaryKey(Integer id);
+
+ int insert(Category record);
+
+ int insertSelective(Category record);
+
+ List selectByExample(CategoryExample example);
+
+ Category selectByPrimaryKey(Integer id);
+
+ int updateByExampleSelective(@Param("record") Category record, @Param("example") CategoryExample example);
+
+ int updateByExample(@Param("record") Category record, @Param("example") CategoryExample example);
+
+ int updateByPrimaryKeySelective(Category record);
+
+ int updateByPrimaryKey(Category record);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/ScreenBulletMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/ScreenBulletMapper.java
new file mode 100644
index 0000000..dbf56ac
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/ScreenBulletMapper.java
@@ -0,0 +1,31 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.ScreenBullet;
+import xyz.zinglizingli.books.po.ScreenBulletExample;
+
+import java.util.List;
+
+public interface ScreenBulletMapper {
+ int countByExample(ScreenBulletExample example);
+
+ int deleteByExample(ScreenBulletExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(ScreenBullet record);
+
+ int insertSelective(ScreenBullet record);
+
+ List selectByExample(ScreenBulletExample example);
+
+ ScreenBullet selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") ScreenBullet record, @Param("example") ScreenBulletExample example);
+
+ int updateByExample(@Param("record") ScreenBullet record, @Param("example") ScreenBulletExample example);
+
+ int updateByPrimaryKeySelective(ScreenBullet record);
+
+ int updateByPrimaryKey(ScreenBullet record);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/UserMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/UserMapper.java
new file mode 100644
index 0000000..a38478a
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/UserMapper.java
@@ -0,0 +1,31 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.User;
+import xyz.zinglizingli.books.po.UserExample;
+
+import java.util.List;
+
+public interface UserMapper {
+ int countByExample(UserExample example);
+
+ int deleteByExample(UserExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(User record);
+
+ int insertSelective(User record);
+
+ List selectByExample(UserExample example);
+
+ User selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);
+
+ int updateByExample(@Param("record") User record, @Param("example") UserExample example);
+
+ int updateByPrimaryKeySelective(User record);
+
+ int updateByPrimaryKey(User record);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/mapper/UserRefBookMapper.java b/src/main/java/xyz/zinglizingli/books/mapper/UserRefBookMapper.java
new file mode 100644
index 0000000..34414b1
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/mapper/UserRefBookMapper.java
@@ -0,0 +1,31 @@
+package xyz.zinglizingli.books.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import xyz.zinglizingli.books.po.UserRefBook;
+import xyz.zinglizingli.books.po.UserRefBookExample;
+
+import java.util.List;
+
+public interface UserRefBookMapper {
+ int countByExample(UserRefBookExample example);
+
+ int deleteByExample(UserRefBookExample example);
+
+ int deleteByPrimaryKey(Long id);
+
+ int insert(UserRefBook record);
+
+ int insertSelective(UserRefBook record);
+
+ List selectByExample(UserRefBookExample example);
+
+ UserRefBook selectByPrimaryKey(Long id);
+
+ int updateByExampleSelective(@Param("record") UserRefBook record, @Param("example") UserRefBookExample example);
+
+ int updateByExample(@Param("record") UserRefBook record, @Param("example") UserRefBookExample example);
+
+ int updateByPrimaryKeySelective(UserRefBook record);
+
+ int updateByPrimaryKey(UserRefBook record);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/Book.java b/src/main/java/xyz/zinglizingli/books/po/Book.java
new file mode 100644
index 0000000..ea8f628
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/Book.java
@@ -0,0 +1,149 @@
+package xyz.zinglizingli.books.po;
+
+
+import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class Book implements Serializable{
+
+ private Long id;
+
+ private Integer catid;
+
+ private String picUrl;
+
+ private String bookName;
+
+ private String author;
+
+ private String bookDesc;
+
+ private Float score;
+
+ private String bookStatus;
+
+ private Long visitCount;
+
+ private Date updateTime;
+
+ private String updateTimeStr;
+
+ private Integer softCat;
+
+ private String softTag;
+
+ public Integer getSoftCat() {
+ return softCat;
+ }
+
+ public void setSoftCat(Integer softCat) {
+ this.softCat = softCat;
+ }
+
+ public String getSoftTag() {
+ return softTag;
+ }
+
+ public void setSoftTag(String softTag) {
+ this.softTag = softTag;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getCatid() {
+ return catid;
+ }
+
+ public void setCatid(Integer catid) {
+ this.catid = catid;
+ }
+
+ public String getPicUrl() {
+ return picUrl;
+ }
+
+ public void setPicUrl(String picUrl) {
+ this.picUrl = picUrl == null ? null : picUrl.trim();
+ }
+
+ public String getBookName() {
+ return bookName;
+ }
+
+ public void setBookName(String bookName) {
+ this.bookName = bookName == null ? null : bookName.trim();
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author == null ? null : author.trim();
+ }
+
+ public String getBookDesc() {
+ return bookDesc;
+ }
+
+ public void setBookDesc(String bookDesc) {
+ this.bookDesc = bookDesc == null ? null : bookDesc.trim();
+ }
+
+ public Float getScore() {
+ return score;
+ }
+
+ public void setScore(Float score) {
+ this.score = score;
+ }
+
+ public String getBookStatus() {
+ return bookStatus;
+ }
+
+ public void setBookStatus(String bookStatus) {
+ this.bookStatus = bookStatus == null ? null : bookStatus.trim();
+ }
+
+ public Long getVisitCount() {
+ return visitCount;
+ }
+
+ public void setVisitCount(Long visitCount) {
+ this.visitCount = visitCount;
+ }
+
+ public Date getUpdateTime()
+ {
+ SimpleDateFormat format = new SimpleDateFormat();
+ try {
+ if(this.updateTimeStr != null) {
+ updateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.updateTimeStr);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getUpdateTimeStr() {
+ return updateTimeStr;
+ }
+
+ public void setUpdateTimeStr(String updateTimeStr) {
+ this.updateTimeStr = updateTimeStr;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/BookContent.java b/src/main/java/xyz/zinglizingli/books/po/BookContent.java
new file mode 100644
index 0000000..47e748d
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/BookContent.java
@@ -0,0 +1,55 @@
+package xyz.zinglizingli.books.po;
+
+import java.io.Serializable;
+
+public class BookContent implements Serializable {
+ private Long id;
+
+ private Long bookId;
+
+ private Long indexId;
+
+ private Integer indexNum;
+
+ private String content;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getBookId() {
+ return bookId;
+ }
+
+ public void setBookId(Long bookId) {
+ this.bookId = bookId;
+ }
+
+ public Long getIndexId() {
+ return indexId;
+ }
+
+ public void setIndexId(Long indexId) {
+ this.indexId = indexId;
+ }
+
+ public Integer getIndexNum() {
+ return indexNum;
+ }
+
+ public void setIndexNum(Integer indexNum) {
+ this.indexNum = indexNum;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content == null ? null : content.trim();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/BookContentExample.java b/src/main/java/xyz/zinglizingli/books/po/BookContentExample.java
new file mode 100644
index 0000000..b3d08f5
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/BookContentExample.java
@@ -0,0 +1,510 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BookContentExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public BookContentExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNull() {
+ addCriterion("book_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNotNull() {
+ addCriterion("book_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdEqualTo(Long value) {
+ addCriterion("book_id =", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotEqualTo(Long value) {
+ addCriterion("book_id <>", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThan(Long value) {
+ addCriterion("book_id >", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("book_id >=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThan(Long value) {
+ addCriterion("book_id <", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThanOrEqualTo(Long value) {
+ addCriterion("book_id <=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIn(List values) {
+ addCriterion("book_id in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotIn(List values) {
+ addCriterion("book_id not in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdBetween(Long value1, Long value2) {
+ addCriterion("book_id between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotBetween(Long value1, Long value2) {
+ addCriterion("book_id not between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdIsNull() {
+ addCriterion("index_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdIsNotNull() {
+ addCriterion("index_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdEqualTo(Long value) {
+ addCriterion("index_id =", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdNotEqualTo(Long value) {
+ addCriterion("index_id <>", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdGreaterThan(Long value) {
+ addCriterion("index_id >", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("index_id >=", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdLessThan(Long value) {
+ addCriterion("index_id <", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdLessThanOrEqualTo(Long value) {
+ addCriterion("index_id <=", value, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdIn(List values) {
+ addCriterion("index_id in", values, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdNotIn(List values) {
+ addCriterion("index_id not in", values, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdBetween(Long value1, Long value2) {
+ addCriterion("index_id between", value1, value2, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexIdNotBetween(Long value1, Long value2) {
+ addCriterion("index_id not between", value1, value2, "indexId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIsNull() {
+ addCriterion("index_num is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIsNotNull() {
+ addCriterion("index_num is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumEqualTo(Integer value) {
+ addCriterion("index_num =", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotEqualTo(Integer value) {
+ addCriterion("index_num <>", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumGreaterThan(Integer value) {
+ addCriterion("index_num >", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumGreaterThanOrEqualTo(Integer value) {
+ addCriterion("index_num >=", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumLessThan(Integer value) {
+ addCriterion("index_num <", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumLessThanOrEqualTo(Integer value) {
+ addCriterion("index_num <=", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIn(List values) {
+ addCriterion("index_num in", values, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotIn(List values) {
+ addCriterion("index_num not in", values, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumBetween(Integer value1, Integer value2) {
+ addCriterion("index_num between", value1, value2, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotBetween(Integer value1, Integer value2) {
+ addCriterion("index_num not between", value1, value2, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIsNull() {
+ addCriterion("content is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIsNotNull() {
+ addCriterion("content is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentEqualTo(String value) {
+ addCriterion("content =", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentNotEqualTo(String value) {
+ addCriterion("content <>", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentGreaterThan(String value) {
+ addCriterion("content >", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentGreaterThanOrEqualTo(String value) {
+ addCriterion("content >=", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentLessThan(String value) {
+ addCriterion("content <", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentLessThanOrEqualTo(String value) {
+ addCriterion("content <=", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentLike(String value) {
+ addCriterion("content like", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentNotLike(String value) {
+ addCriterion("content not like", value, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIn(List values) {
+ addCriterion("content in", values, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentNotIn(List values) {
+ addCriterion("content not in", values, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentBetween(String value1, String value2) {
+ addCriterion("content between", value1, value2, "content");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentNotBetween(String value1, String value2) {
+ addCriterion("content not between", value1, value2, "content");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/BookExample.java b/src/main/java/xyz/zinglizingli/books/po/BookExample.java
new file mode 100644
index 0000000..9eba411
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/BookExample.java
@@ -0,0 +1,851 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class BookExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public BookExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidIsNull() {
+ addCriterion("catId is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidIsNotNull() {
+ addCriterion("catId is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidEqualTo(Integer value) {
+ addCriterion("catId =", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidNotEqualTo(Integer value) {
+ addCriterion("catId <>", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidGreaterThan(Integer value) {
+ addCriterion("catId >", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidGreaterThanOrEqualTo(Integer value) {
+ addCriterion("catId >=", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidLessThan(Integer value) {
+ addCriterion("catId <", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidLessThanOrEqualTo(Integer value) {
+ addCriterion("catId <=", value, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidIn(List values) {
+ addCriterion("catId in", values, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidNotIn(List values) {
+ addCriterion("catId not in", values, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidBetween(Integer value1, Integer value2) {
+ addCriterion("catId between", value1, value2, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andCatidNotBetween(Integer value1, Integer value2) {
+ addCriterion("catId not between", value1, value2, "catid");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlIsNull() {
+ addCriterion("pic_url is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlIsNotNull() {
+ addCriterion("pic_url is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlEqualTo(String value) {
+ addCriterion("pic_url =", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlNotEqualTo(String value) {
+ addCriterion("pic_url <>", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlGreaterThan(String value) {
+ addCriterion("pic_url >", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlGreaterThanOrEqualTo(String value) {
+ addCriterion("pic_url >=", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlLessThan(String value) {
+ addCriterion("pic_url <", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlLessThanOrEqualTo(String value) {
+ addCriterion("pic_url <=", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlLike(String value) {
+ addCriterion("pic_url like", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlNotLike(String value) {
+ addCriterion("pic_url not like", value, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlIn(List values) {
+ addCriterion("pic_url in", values, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlNotIn(List values) {
+ addCriterion("pic_url not in", values, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlBetween(String value1, String value2) {
+ addCriterion("pic_url between", value1, value2, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andPicUrlNotBetween(String value1, String value2) {
+ addCriterion("pic_url not between", value1, value2, "picUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameIsNull() {
+ addCriterion("book_name is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameIsNotNull() {
+ addCriterion("book_name is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameEqualTo(String value) {
+ addCriterion("book_name =", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameNotEqualTo(String value) {
+ addCriterion("book_name <>", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameGreaterThan(String value) {
+ addCriterion("book_name >", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameGreaterThanOrEqualTo(String value) {
+ addCriterion("book_name >=", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameLessThan(String value) {
+ addCriterion("book_name <", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameLessThanOrEqualTo(String value) {
+ addCriterion("book_name <=", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameLike(String value) {
+ addCriterion("book_name like", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameNotLike(String value) {
+ addCriterion("book_name not like", value, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameIn(List values) {
+ addCriterion("book_name in", values, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameNotIn(List values) {
+ addCriterion("book_name not in", values, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameBetween(String value1, String value2) {
+ addCriterion("book_name between", value1, value2, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookNameNotBetween(String value1, String value2) {
+ addCriterion("book_name not between", value1, value2, "bookName");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorIsNull() {
+ addCriterion("author is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorIsNotNull() {
+ addCriterion("author is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorEqualTo(String value) {
+ addCriterion("author =", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorNotEqualTo(String value) {
+ addCriterion("author <>", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorGreaterThan(String value) {
+ addCriterion("author >", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorGreaterThanOrEqualTo(String value) {
+ addCriterion("author >=", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorLessThan(String value) {
+ addCriterion("author <", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorLessThanOrEqualTo(String value) {
+ addCriterion("author <=", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorLike(String value) {
+ addCriterion("author like", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorNotLike(String value) {
+ addCriterion("author not like", value, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorIn(List values) {
+ addCriterion("author in", values, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorNotIn(List values) {
+ addCriterion("author not in", values, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorBetween(String value1, String value2) {
+ addCriterion("author between", value1, value2, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andAuthorNotBetween(String value1, String value2) {
+ addCriterion("author not between", value1, value2, "author");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescIsNull() {
+ addCriterion("book_desc is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescIsNotNull() {
+ addCriterion("book_desc is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescEqualTo(String value) {
+ addCriterion("book_desc =", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescNotEqualTo(String value) {
+ addCriterion("book_desc <>", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescGreaterThan(String value) {
+ addCriterion("book_desc >", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescGreaterThanOrEqualTo(String value) {
+ addCriterion("book_desc >=", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescLessThan(String value) {
+ addCriterion("book_desc <", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescLessThanOrEqualTo(String value) {
+ addCriterion("book_desc <=", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescLike(String value) {
+ addCriterion("book_desc like", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescNotLike(String value) {
+ addCriterion("book_desc not like", value, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescIn(List values) {
+ addCriterion("book_desc in", values, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescNotIn(List values) {
+ addCriterion("book_desc not in", values, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescBetween(String value1, String value2) {
+ addCriterion("book_desc between", value1, value2, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookDescNotBetween(String value1, String value2) {
+ addCriterion("book_desc not between", value1, value2, "bookDesc");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreIsNull() {
+ addCriterion("score is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreIsNotNull() {
+ addCriterion("score is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreEqualTo(Float value) {
+ addCriterion("score =", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreNotEqualTo(Float value) {
+ addCriterion("score <>", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreGreaterThan(Float value) {
+ addCriterion("score >", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreGreaterThanOrEqualTo(Float value) {
+ addCriterion("score >=", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreLessThan(Float value) {
+ addCriterion("score <", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreLessThanOrEqualTo(Float value) {
+ addCriterion("score <=", value, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreIn(List values) {
+ addCriterion("score in", values, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreNotIn(List values) {
+ addCriterion("score not in", values, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreBetween(Float value1, Float value2) {
+ addCriterion("score between", value1, value2, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andScoreNotBetween(Float value1, Float value2) {
+ addCriterion("score not between", value1, value2, "score");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusIsNull() {
+ addCriterion("book_status is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusIsNotNull() {
+ addCriterion("book_status is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusEqualTo(String value) {
+ addCriterion("book_status =", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusNotEqualTo(String value) {
+ addCriterion("book_status <>", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusGreaterThan(String value) {
+ addCriterion("book_status >", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusGreaterThanOrEqualTo(String value) {
+ addCriterion("book_status >=", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusLessThan(String value) {
+ addCriterion("book_status <", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusLessThanOrEqualTo(String value) {
+ addCriterion("book_status <=", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusLike(String value) {
+ addCriterion("book_status like", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusNotLike(String value) {
+ addCriterion("book_status not like", value, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusIn(List values) {
+ addCriterion("book_status in", values, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusNotIn(List values) {
+ addCriterion("book_status not in", values, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusBetween(String value1, String value2) {
+ addCriterion("book_status between", value1, value2, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookStatusNotBetween(String value1, String value2) {
+ addCriterion("book_status not between", value1, value2, "bookStatus");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountIsNull() {
+ addCriterion("visit_count is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountIsNotNull() {
+ addCriterion("visit_count is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountEqualTo(Long value) {
+ addCriterion("visit_count =", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountNotEqualTo(Long value) {
+ addCriterion("visit_count <>", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountGreaterThan(Long value) {
+ addCriterion("visit_count >", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountGreaterThanOrEqualTo(Long value) {
+ addCriterion("visit_count >=", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountLessThan(Long value) {
+ addCriterion("visit_count <", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountLessThanOrEqualTo(Long value) {
+ addCriterion("visit_count <=", value, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountIn(List values) {
+ addCriterion("visit_count in", values, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountNotIn(List values) {
+ addCriterion("visit_count not in", values, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountBetween(Long value1, Long value2) {
+ addCriterion("visit_count between", value1, value2, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andVisitCountNotBetween(Long value1, Long value2) {
+ addCriterion("visit_count not between", value1, value2, "visitCount");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeIsNull() {
+ addCriterion("update_time is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeIsNotNull() {
+ addCriterion("update_time is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeEqualTo(Date value) {
+ addCriterion("update_time =", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeNotEqualTo(Date value) {
+ addCriterion("update_time <>", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeGreaterThan(Date value) {
+ addCriterion("update_time >", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeGreaterThanOrEqualTo(Date value) {
+ addCriterion("update_time >=", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeLessThan(Date value) {
+ addCriterion("update_time <", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeLessThanOrEqualTo(Date value) {
+ addCriterion("update_time <=", value, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeIn(List values) {
+ addCriterion("update_time in", values, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeNotIn(List values) {
+ addCriterion("update_time not in", values, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeBetween(Date value1, Date value2) {
+ addCriterion("update_time between", value1, value2, "updateTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andUpdateTimeNotBetween(Date value1, Date value2) {
+ addCriterion("update_time not between", value1, value2, "updateTime");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/BookIndex.java b/src/main/java/xyz/zinglizingli/books/po/BookIndex.java
new file mode 100644
index 0000000..5451833
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/BookIndex.java
@@ -0,0 +1,45 @@
+package xyz.zinglizingli.books.po;
+
+import java.io.Serializable;
+
+public class BookIndex implements Serializable {
+ private Long id;
+
+ private Long bookId;
+
+ private Integer indexNum;
+
+ private String indexName;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getBookId() {
+ return bookId;
+ }
+
+ public void setBookId(Long bookId) {
+ this.bookId = bookId;
+ }
+
+ public Integer getIndexNum() {
+ return indexNum;
+ }
+
+ public void setIndexNum(Integer indexNum) {
+ this.indexNum = indexNum;
+ }
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public void setIndexName(String indexName) {
+ this.indexName = indexName == null ? null : indexName.trim();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/BookIndexExample.java b/src/main/java/xyz/zinglizingli/books/po/BookIndexExample.java
new file mode 100644
index 0000000..5ad0253
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/BookIndexExample.java
@@ -0,0 +1,450 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BookIndexExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public BookIndexExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNull() {
+ addCriterion("book_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNotNull() {
+ addCriterion("book_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdEqualTo(Long value) {
+ addCriterion("book_id =", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotEqualTo(Long value) {
+ addCriterion("book_id <>", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThan(Long value) {
+ addCriterion("book_id >", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("book_id >=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThan(Long value) {
+ addCriterion("book_id <", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThanOrEqualTo(Long value) {
+ addCriterion("book_id <=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIn(List values) {
+ addCriterion("book_id in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotIn(List values) {
+ addCriterion("book_id not in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdBetween(Long value1, Long value2) {
+ addCriterion("book_id between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotBetween(Long value1, Long value2) {
+ addCriterion("book_id not between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIsNull() {
+ addCriterion("index_num is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIsNotNull() {
+ addCriterion("index_num is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumEqualTo(Integer value) {
+ addCriterion("index_num =", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotEqualTo(Integer value) {
+ addCriterion("index_num <>", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumGreaterThan(Integer value) {
+ addCriterion("index_num >", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumGreaterThanOrEqualTo(Integer value) {
+ addCriterion("index_num >=", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumLessThan(Integer value) {
+ addCriterion("index_num <", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumLessThanOrEqualTo(Integer value) {
+ addCriterion("index_num <=", value, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumIn(List values) {
+ addCriterion("index_num in", values, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotIn(List values) {
+ addCriterion("index_num not in", values, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumBetween(Integer value1, Integer value2) {
+ addCriterion("index_num between", value1, value2, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNumNotBetween(Integer value1, Integer value2) {
+ addCriterion("index_num not between", value1, value2, "indexNum");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameIsNull() {
+ addCriterion("index_name is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameIsNotNull() {
+ addCriterion("index_name is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameEqualTo(String value) {
+ addCriterion("index_name =", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameNotEqualTo(String value) {
+ addCriterion("index_name <>", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameGreaterThan(String value) {
+ addCriterion("index_name >", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameGreaterThanOrEqualTo(String value) {
+ addCriterion("index_name >=", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameLessThan(String value) {
+ addCriterion("index_name <", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameLessThanOrEqualTo(String value) {
+ addCriterion("index_name <=", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameLike(String value) {
+ addCriterion("index_name like", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameNotLike(String value) {
+ addCriterion("index_name not like", value, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameIn(List values) {
+ addCriterion("index_name in", values, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameNotIn(List values) {
+ addCriterion("index_name not in", values, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameBetween(String value1, String value2) {
+ addCriterion("index_name between", value1, value2, "indexName");
+ return (Criteria) this;
+ }
+
+ public Criteria andIndexNameNotBetween(String value1, String value2) {
+ addCriterion("index_name not between", value1, value2, "indexName");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/Category.java b/src/main/java/xyz/zinglizingli/books/po/Category.java
new file mode 100644
index 0000000..a04cce0
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/Category.java
@@ -0,0 +1,53 @@
+package xyz.zinglizingli.books.po;
+
+public class Category {
+ private Integer id;
+
+ private String name;
+
+ private Byte sort;
+
+ private String getUrl;
+
+ private String reqUrl;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name == null ? null : name.trim();
+ }
+
+ public Byte getSort() {
+ return sort;
+ }
+
+ public void setSort(Byte sort) {
+ this.sort = sort;
+ }
+
+ public String getGetUrl() {
+ return getUrl;
+ }
+
+ public void setGetUrl(String getUrl) {
+ this.getUrl = getUrl == null ? null : getUrl.trim();
+ }
+
+ public String getReqUrl() {
+ return reqUrl;
+ }
+
+ public void setReqUrl(String reqUrl) {
+ this.reqUrl = reqUrl == null ? null : reqUrl.trim();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/CategoryExample.java b/src/main/java/xyz/zinglizingli/books/po/CategoryExample.java
new file mode 100644
index 0000000..583352a
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/CategoryExample.java
@@ -0,0 +1,530 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CategoryExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public CategoryExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Integer value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Integer value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Integer value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Integer value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Integer value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Integer value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Integer value1, Integer value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Integer value1, Integer value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIsNull() {
+ addCriterion("name is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIsNotNull() {
+ addCriterion("name is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameEqualTo(String value) {
+ addCriterion("name =", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotEqualTo(String value) {
+ addCriterion("name <>", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameGreaterThan(String value) {
+ addCriterion("name >", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameGreaterThanOrEqualTo(String value) {
+ addCriterion("name >=", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLessThan(String value) {
+ addCriterion("name <", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLessThanOrEqualTo(String value) {
+ addCriterion("name <=", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameLike(String value) {
+ addCriterion("name like", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotLike(String value) {
+ addCriterion("name not like", value, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameIn(List values) {
+ addCriterion("name in", values, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotIn(List values) {
+ addCriterion("name not in", values, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameBetween(String value1, String value2) {
+ addCriterion("name between", value1, value2, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andNameNotBetween(String value1, String value2) {
+ addCriterion("name not between", value1, value2, "name");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortIsNull() {
+ addCriterion("sort is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortIsNotNull() {
+ addCriterion("sort is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortEqualTo(Byte value) {
+ addCriterion("sort =", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortNotEqualTo(Byte value) {
+ addCriterion("sort <>", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortGreaterThan(Byte value) {
+ addCriterion("sort >", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortGreaterThanOrEqualTo(Byte value) {
+ addCriterion("sort >=", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortLessThan(Byte value) {
+ addCriterion("sort <", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortLessThanOrEqualTo(Byte value) {
+ addCriterion("sort <=", value, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortIn(List values) {
+ addCriterion("sort in", values, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortNotIn(List values) {
+ addCriterion("sort not in", values, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortBetween(Byte value1, Byte value2) {
+ addCriterion("sort between", value1, value2, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andSortNotBetween(Byte value1, Byte value2) {
+ addCriterion("sort not between", value1, value2, "sort");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlIsNull() {
+ addCriterion("get_url is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlIsNotNull() {
+ addCriterion("get_url is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlEqualTo(String value) {
+ addCriterion("get_url =", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlNotEqualTo(String value) {
+ addCriterion("get_url <>", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlGreaterThan(String value) {
+ addCriterion("get_url >", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlGreaterThanOrEqualTo(String value) {
+ addCriterion("get_url >=", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlLessThan(String value) {
+ addCriterion("get_url <", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlLessThanOrEqualTo(String value) {
+ addCriterion("get_url <=", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlLike(String value) {
+ addCriterion("get_url like", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlNotLike(String value) {
+ addCriterion("get_url not like", value, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlIn(List values) {
+ addCriterion("get_url in", values, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlNotIn(List values) {
+ addCriterion("get_url not in", values, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlBetween(String value1, String value2) {
+ addCriterion("get_url between", value1, value2, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andGetUrlNotBetween(String value1, String value2) {
+ addCriterion("get_url not between", value1, value2, "getUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlIsNull() {
+ addCriterion("req_url is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlIsNotNull() {
+ addCriterion("req_url is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlEqualTo(String value) {
+ addCriterion("req_url =", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlNotEqualTo(String value) {
+ addCriterion("req_url <>", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlGreaterThan(String value) {
+ addCriterion("req_url >", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlGreaterThanOrEqualTo(String value) {
+ addCriterion("req_url >=", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlLessThan(String value) {
+ addCriterion("req_url <", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlLessThanOrEqualTo(String value) {
+ addCriterion("req_url <=", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlLike(String value) {
+ addCriterion("req_url like", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlNotLike(String value) {
+ addCriterion("req_url not like", value, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlIn(List values) {
+ addCriterion("req_url in", values, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlNotIn(List values) {
+ addCriterion("req_url not in", values, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlBetween(String value1, String value2) {
+ addCriterion("req_url between", value1, value2, "reqUrl");
+ return (Criteria) this;
+ }
+
+ public Criteria andReqUrlNotBetween(String value1, String value2) {
+ addCriterion("req_url not between", value1, value2, "reqUrl");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/ScreenBullet.java b/src/main/java/xyz/zinglizingli/books/po/ScreenBullet.java
new file mode 100644
index 0000000..e8aadef
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/ScreenBullet.java
@@ -0,0 +1,45 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.Date;
+
+public class ScreenBullet {
+ private Long id;
+
+ private Long contentId;
+
+ private String screenBullet;
+
+ private Date createTime;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getContentId() {
+ return contentId;
+ }
+
+ public void setContentId(Long contentId) {
+ this.contentId = contentId;
+ }
+
+ public String getScreenBullet() {
+ return screenBullet;
+ }
+
+ public void setScreenBullet(String screenBullet) {
+ this.screenBullet = screenBullet == null ? null : screenBullet.trim();
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/ScreenBulletExample.java b/src/main/java/xyz/zinglizingli/books/po/ScreenBulletExample.java
new file mode 100644
index 0000000..b18f015
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/ScreenBulletExample.java
@@ -0,0 +1,451 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class ScreenBulletExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public ScreenBulletExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdIsNull() {
+ addCriterion("content_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdIsNotNull() {
+ addCriterion("content_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdEqualTo(Long value) {
+ addCriterion("content_id =", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdNotEqualTo(Long value) {
+ addCriterion("content_id <>", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdGreaterThan(Long value) {
+ addCriterion("content_id >", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("content_id >=", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdLessThan(Long value) {
+ addCriterion("content_id <", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdLessThanOrEqualTo(Long value) {
+ addCriterion("content_id <=", value, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdIn(List values) {
+ addCriterion("content_id in", values, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdNotIn(List values) {
+ addCriterion("content_id not in", values, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdBetween(Long value1, Long value2) {
+ addCriterion("content_id between", value1, value2, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andContentIdNotBetween(Long value1, Long value2) {
+ addCriterion("content_id not between", value1, value2, "contentId");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletIsNull() {
+ addCriterion("screen_bullet is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletIsNotNull() {
+ addCriterion("screen_bullet is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletEqualTo(String value) {
+ addCriterion("screen_bullet =", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletNotEqualTo(String value) {
+ addCriterion("screen_bullet <>", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletGreaterThan(String value) {
+ addCriterion("screen_bullet >", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletGreaterThanOrEqualTo(String value) {
+ addCriterion("screen_bullet >=", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletLessThan(String value) {
+ addCriterion("screen_bullet <", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletLessThanOrEqualTo(String value) {
+ addCriterion("screen_bullet <=", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletLike(String value) {
+ addCriterion("screen_bullet like", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletNotLike(String value) {
+ addCriterion("screen_bullet not like", value, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletIn(List values) {
+ addCriterion("screen_bullet in", values, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletNotIn(List values) {
+ addCriterion("screen_bullet not in", values, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletBetween(String value1, String value2) {
+ addCriterion("screen_bullet between", value1, value2, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andScreenBulletNotBetween(String value1, String value2) {
+ addCriterion("screen_bullet not between", value1, value2, "screenBullet");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeIsNull() {
+ addCriterion("create_time is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeIsNotNull() {
+ addCriterion("create_time is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeEqualTo(Date value) {
+ addCriterion("create_time =", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeNotEqualTo(Date value) {
+ addCriterion("create_time <>", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeGreaterThan(Date value) {
+ addCriterion("create_time >", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeGreaterThanOrEqualTo(Date value) {
+ addCriterion("create_time >=", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeLessThan(Date value) {
+ addCriterion("create_time <", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeLessThanOrEqualTo(Date value) {
+ addCriterion("create_time <=", value, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeIn(List values) {
+ addCriterion("create_time in", values, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeNotIn(List values) {
+ addCriterion("create_time not in", values, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeBetween(Date value1, Date value2) {
+ addCriterion("create_time between", value1, value2, "createTime");
+ return (Criteria) this;
+ }
+
+ public Criteria andCreateTimeNotBetween(Date value1, Date value2) {
+ addCriterion("create_time not between", value1, value2, "createTime");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/User.java b/src/main/java/xyz/zinglizingli/books/po/User.java
new file mode 100644
index 0000000..68baa75
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/User.java
@@ -0,0 +1,33 @@
+package xyz.zinglizingli.books.po;
+
+public class User {
+ private Long id;
+
+ private String loginName;
+
+ private String password;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLoginName() {
+ return loginName;
+ }
+
+ public void setLoginName(String loginName) {
+ this.loginName = loginName == null ? null : loginName.trim();
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password == null ? null : password.trim();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/UserExample.java b/src/main/java/xyz/zinglizingli/books/po/UserExample.java
new file mode 100644
index 0000000..1093788
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/UserExample.java
@@ -0,0 +1,400 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public UserExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameIsNull() {
+ addCriterion("login_name is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameIsNotNull() {
+ addCriterion("login_name is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameEqualTo(String value) {
+ addCriterion("login_name =", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameNotEqualTo(String value) {
+ addCriterion("login_name <>", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameGreaterThan(String value) {
+ addCriterion("login_name >", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameGreaterThanOrEqualTo(String value) {
+ addCriterion("login_name >=", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameLessThan(String value) {
+ addCriterion("login_name <", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameLessThanOrEqualTo(String value) {
+ addCriterion("login_name <=", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameLike(String value) {
+ addCriterion("login_name like", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameNotLike(String value) {
+ addCriterion("login_name not like", value, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameIn(List values) {
+ addCriterion("login_name in", values, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameNotIn(List values) {
+ addCriterion("login_name not in", values, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameBetween(String value1, String value2) {
+ addCriterion("login_name between", value1, value2, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andLoginNameNotBetween(String value1, String value2) {
+ addCriterion("login_name not between", value1, value2, "loginName");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordIsNull() {
+ addCriterion("password is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordIsNotNull() {
+ addCriterion("password is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordEqualTo(String value) {
+ addCriterion("password =", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordNotEqualTo(String value) {
+ addCriterion("password <>", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordGreaterThan(String value) {
+ addCriterion("password >", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordGreaterThanOrEqualTo(String value) {
+ addCriterion("password >=", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordLessThan(String value) {
+ addCriterion("password <", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordLessThanOrEqualTo(String value) {
+ addCriterion("password <=", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordLike(String value) {
+ addCriterion("password like", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordNotLike(String value) {
+ addCriterion("password not like", value, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordIn(List values) {
+ addCriterion("password in", values, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordNotIn(List values) {
+ addCriterion("password not in", values, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordBetween(String value1, String value2) {
+ addCriterion("password between", value1, value2, "password");
+ return (Criteria) this;
+ }
+
+ public Criteria andPasswordNotBetween(String value1, String value2) {
+ addCriterion("password not between", value1, value2, "password");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/UserRefBook.java b/src/main/java/xyz/zinglizingli/books/po/UserRefBook.java
new file mode 100644
index 0000000..a1e058e
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/UserRefBook.java
@@ -0,0 +1,33 @@
+package xyz.zinglizingli.books.po;
+
+public class UserRefBook {
+ private Long id;
+
+ private Long userId;
+
+ private Long bookId;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public Long getBookId() {
+ return bookId;
+ }
+
+ public void setBookId(Long bookId) {
+ this.bookId = bookId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/po/UserRefBookExample.java b/src/main/java/xyz/zinglizingli/books/po/UserRefBookExample.java
new file mode 100644
index 0000000..6b68a43
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/po/UserRefBookExample.java
@@ -0,0 +1,380 @@
+package xyz.zinglizingli.books.po;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserRefBookExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public UserRefBookExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(Long value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(Long value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(Long value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(Long value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(Long value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(Long value1, Long value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(Long value1, Long value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdIsNull() {
+ addCriterion("user_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdIsNotNull() {
+ addCriterion("user_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdEqualTo(Long value) {
+ addCriterion("user_id =", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdNotEqualTo(Long value) {
+ addCriterion("user_id <>", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdGreaterThan(Long value) {
+ addCriterion("user_id >", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("user_id >=", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdLessThan(Long value) {
+ addCriterion("user_id <", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdLessThanOrEqualTo(Long value) {
+ addCriterion("user_id <=", value, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdIn(List values) {
+ addCriterion("user_id in", values, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdNotIn(List values) {
+ addCriterion("user_id not in", values, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdBetween(Long value1, Long value2) {
+ addCriterion("user_id between", value1, value2, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andUserIdNotBetween(Long value1, Long value2) {
+ addCriterion("user_id not between", value1, value2, "userId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNull() {
+ addCriterion("book_id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIsNotNull() {
+ addCriterion("book_id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdEqualTo(Long value) {
+ addCriterion("book_id =", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotEqualTo(Long value) {
+ addCriterion("book_id <>", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThan(Long value) {
+ addCriterion("book_id >", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdGreaterThanOrEqualTo(Long value) {
+ addCriterion("book_id >=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThan(Long value) {
+ addCriterion("book_id <", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdLessThanOrEqualTo(Long value) {
+ addCriterion("book_id <=", value, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdIn(List values) {
+ addCriterion("book_id in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotIn(List values) {
+ addCriterion("book_id not in", values, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdBetween(Long value1, Long value2) {
+ addCriterion("book_id between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+
+ public Criteria andBookIdNotBetween(Long value1, Long value2) {
+ addCriterion("book_id not between", value1, value2, "bookId");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/service/BookService.java b/src/main/java/xyz/zinglizingli/books/service/BookService.java
new file mode 100644
index 0000000..6da60ce
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/service/BookService.java
@@ -0,0 +1,502 @@
+package xyz.zinglizingli.books.service;
+
+import com.github.pagehelper.PageHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import tk.mybatis.orderbyhelper.OrderByHelper;
+import xyz.zinglizingli.books.constant.CacheKeyConstans;
+import xyz.zinglizingli.books.mapper.BookContentMapper;
+import xyz.zinglizingli.books.mapper.BookIndexMapper;
+import xyz.zinglizingli.books.mapper.BookMapper;
+import xyz.zinglizingli.books.mapper.ScreenBulletMapper;
+import xyz.zinglizingli.books.po.*;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+import xyz.zinglizingli.search.schedule.SendUrlSchedule;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+
+import java.util.*;
+
+@Service
+public class BookService {
+
+ @Autowired
+ private BookMapper bookMapper;
+
+ @Autowired
+ private BookIndexMapper bookIndexMapper;
+
+ @Autowired
+ private BookContentMapper bookContentMapper;
+
+ @Autowired
+ private ScreenBulletMapper screenBulletMapper;
+
+ @Autowired
+ private CommonCacheUtil cacheUtil;
+
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+
+ private Logger log = LoggerFactory.getLogger(BookService.class);
+
+
+ public void saveBookAndIndexAndContent(Book book, List bookIndex, List bookContent) {
+ //一次最多只允许插入100条记录,否则影响服务器响应,如果没有插入所有更新,则更新时间设为昨天
+ /*if(bookIndex.size()>100){
+ book.setUpdateTime(new Date(book.getUpdateTime().getTime()-1000*60*60*24));
+ }
+*/
+
+ boolean isUpdate = false;
+ Long bookId = -1l;
+ book.setBookName(book.getBookName().trim());
+ book.setAuthor(book.getAuthor().trim());
+ BookExample example = new BookExample();
+ example.createCriteria().andBookNameEqualTo(book.getBookName()).andAuthorEqualTo(book.getAuthor());
+ List books = bookMapper.selectByExample(example);
+ if (books.size() > 0) {
+ //更新
+ bookId = books.get(0).getId();
+ book.setId(bookId);
+ bookMapper.updateByPrimaryKeySelective(book);
+ isUpdate = true;
+
+ } else {
+ if (book.getVisitCount() == null) {
+ Long visitCount = generateVisiteCount(book.getScore());
+ book.setVisitCount(visitCount);
+ }
+ //插入
+ int rows = bookMapper.insertSelective(book);
+ if (rows > 0) {
+ bookId = book.getId();
+ }
+
+
+ }
+
+ if (bookId >= 0) {
+ //查询目录已存在数量
+ /* BookIndexExample bookIndexExample = new BookIndexExample();
+ bookIndexExample.createCriteria().andBookIdEqualTo(bookId);
+ int indexCount = bookIndexMapper.countByExample(bookIndexExample);*/
+
+ BookIndex lastIndex = null;
+ List newBookIndexList = new ArrayList<>();
+ List newContentList = new ArrayList<>();
+ for (int i = 0; i < bookIndex.size(); i++) {
+ BookContent bookContentItem = bookContent.get(i);
+ if (!bookContentItem.getContent().contains("正在手打中,请稍等片刻,内容更新后,需要重新刷新页面,才能获取最新更新")) {
+ BookIndex bookIndexItem = bookIndex.get(i);
+ bookIndexItem.setBookId(bookId);
+ bookContentItem.setBookId(bookId);
+ //bookContentItem.setIndexId(bookIndexItem.getId());暂时使用bookId和IndexNum查询content
+ bookContentItem.setIndexNum(bookIndexItem.getIndexNum());
+ newBookIndexList.add(bookIndexItem);
+ newContentList.add(bookContentItem);
+ lastIndex = bookIndexItem;
+ }
+ //一次最多只允许插入100条记录,否则影响服务器响应
+ if (isUpdate && i % 100 == 0 && newBookIndexList.size() > 0) {
+ insertIndexListAndContentList(newBookIndexList, newContentList);
+ newBookIndexList = new ArrayList<>();
+ newContentList = new ArrayList<>();
+ try {
+ Thread.sleep(1000 * 60 * 5);
+ } catch (InterruptedException e) {
+ log.error(e.getMessage(), e);
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ }
+
+
+ if (newBookIndexList.size() > 0) {
+ insertIndexListAndContentList(newBookIndexList, newContentList);
+ }
+
+ if (isUpdate) {
+ sendNewstIndex(lastIndex);
+ } else {
+ sendNewstBook(bookId);
+ }
+ cacheUtil.del(CacheKeyConstans.NEWST_BOOK_LIST_KEY);
+
+
+ }
+
+
+ }
+
+ @Transactional
+ public void insertIndexListAndContentList(List newBookIndexList, List newContentList) {
+ bookIndexMapper.insertBatch(newBookIndexList);
+ bookContentMapper.insertBatch(newContentList);
+ }
+
+
+ private Long generateVisiteCount(Float score) {
+ int baseNum = (int) (Math.pow(score * 10, (int) (score - 5)) / 2);
+ return Long.parseLong(baseNum + new Random().nextInt(1000) + "");
+ }
+
+ /**
+ * 分页查询
+ */
+ public List search(int page, int pageSize,
+ String userId, String ids, String keyword, String bookStatus, Integer catId, Integer softCat, String softTag, String sortBy, String sort) {
+
+ if (!StringUtils.isEmpty(userId)) {
+ sortBy = "user_ref_book.id";
+ sort = "DESC";
+ }
+ PageHelper.startPage(page, pageSize);
+ // 排序设置[注意orderby 紧跟分页后面]
+ if (!StringUtils.isEmpty(sortBy)) {
+ OrderByHelper.orderBy(sortBy + " " + sort);
+ }
+
+ List books = bookMapper.search(userId, ids, keyword, catId, softCat, softTag, bookStatus);
+
+ return books;
+
+ }
+
+ public String getCatNameById(Integer catid) {
+ String catName = "其他";
+
+ switch (catid) {
+ case 1: {
+ catName = "玄幻奇幻";
+ break;
+ }
+ case 2: {
+ catName = "武侠仙侠";
+ break;
+ }
+ case 3: {
+ catName = "都市言情";
+ break;
+ }
+ case 4: {
+ catName = "历史军事";
+ break;
+ }
+ case 5: {
+ catName = "科幻灵异";
+ break;
+ }
+ case 6: {
+ catName = "网游竞技";
+ break;
+ }
+ case 7: {
+ catName = "女生频道";
+ break;
+ }
+ case 8: {
+ catName = "轻小说";
+ break;
+ }
+ default: {
+ break;
+ }
+
+
+ }
+ return catName;
+ }
+
+ public Book queryBaseInfo(Long bookId) {
+
+ return bookMapper.selectByPrimaryKey(bookId);
+ }
+
+ public List queryNewIndexList(Long bookId) {
+ PageHelper.startPage(1, 15);
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId);
+ example.setOrderByClause("index_num DESC");
+ return bookIndexMapper.selectByExample(example);
+
+ }
+
+ public List queryAllIndexList(Long bookId) {
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId);
+ example.setOrderByClause("index_num ASC");
+ return bookIndexMapper.selectByExample(example);
+ }
+
+ public BookContent queryBookContent(Long bookId, Integer indexNum) {
+ BookContent content = (BookContent) cacheUtil.getObject(CacheKeyConstans.BOOK_CONTENT_KEY_PREFIX + "_" + bookId + "_" + indexNum);
+ if (content == null) {
+ BookContentExample example = new BookContentExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumEqualTo(indexNum);
+ List bookContents = bookContentMapper.selectByExample(example);
+ content = bookContents.size()>0?bookContents.get(0):null;
+ cacheUtil.setObject(CacheKeyConstans.BOOK_CONTENT_KEY_PREFIX + "_" + bookId + "_" + indexNum, content, 60 * 60 * 24);
+ }
+
+ return content;
+ }
+
+ public void addVisitCount(Long bookId) {
+
+ bookMapper.addVisitCount(bookId);
+ }
+
+ public String queryIndexNameByBookIdAndIndexNum(Long bookId, Integer indexNum) {
+
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumEqualTo(indexNum);
+ return bookIndexMapper.selectByExample(example).get(0).getIndexName();
+ }
+
+ public List queryMaxAndMinIndexNum(Long bookId) {
+ List result = new ArrayList<>();
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId);
+ example.setOrderByClause("index_num desc");
+ List bookIndices = bookIndexMapper.selectByExample(example);
+ if(bookIndices.size()>0) {
+ result.add(bookIndices.get(0).getIndexNum());
+ result.add(bookIndices.get(bookIndices.size() - 1).getIndexNum());
+ }
+ return result;
+ }
+
+ /**
+ * 查询该书籍目录数量
+ */
+ public List queryIndexCountByBookNameAndBAuthor(String bookName, String author) {
+ List result = new ArrayList<>();
+ BookExample example = new BookExample();
+ example.createCriteria().andBookNameEqualTo(bookName).andAuthorEqualTo(author);
+ List books = bookMapper.selectByExample(example);
+ if (books.size() > 0) {
+
+ Long bookId = books.get(0).getId();
+ BookIndexExample bookIndexExample = new BookIndexExample();
+ bookIndexExample.createCriteria().andBookIdEqualTo(bookId);
+ List bookIndices = bookIndexMapper.selectByExample(bookIndexExample);
+ if (bookIndices != null && bookIndices.size() > 0) {
+ for (BookIndex bookIndex : bookIndices) {
+ result.add(bookIndex.getIndexNum());
+ }
+ }
+
+ }
+
+ return result;
+
+ }
+
+ public Book queryRandomBook() {
+
+ return bookMapper.queryRandomBook();
+ }
+
+ public Map queryNewstBook() {
+ final String SENDIDS = "sendWeiboIds";
+ Set sendIds = (Set) cacheUtil.getObject(SENDIDS);
+ if (sendIds == null) {
+ sendIds = new HashSet<>();
+ }
+ String newstIndexName = null;
+ Book book = null;
+ book = bookMapper.queryNewstBook(sendIds);
+ Map data = new HashMap<>();
+ if (book != null && book.getId() != null) {
+ newstIndexName = bookIndexMapper.queryNewstIndexName(book.getId());
+ if (!StringUtils.isEmpty(newstIndexName)) {
+ sendIds.add(book.getId());
+ cacheUtil.setObject(SENDIDS, sendIds, 60 * 60 * 24 * 2);
+ data.put("book", book);
+ data.put("newstIndexName", newstIndexName);
+ }
+ }
+ return data;
+ }
+
+ public String getSoftCatNameById(Integer softCat) {
+ String catName = "其他";
+
+ switch (softCat) {
+ case 21: {
+ catName = "魔幻";
+ break;
+ }
+ case 22: {
+ catName = "玄幻";
+ break;
+ }
+ case 23: {
+ catName = "古风";
+ break;
+ }
+ case 24: {
+ catName = "科幻";
+ break;
+ }
+ case 25: {
+ catName = "校园";
+ break;
+ }
+ case 26: {
+ catName = "都市";
+ break;
+ }
+ case 27: {
+ catName = "游戏";
+ break;
+ }
+ case 28: {
+ catName = "同人";
+ break;
+ }
+ case 29: {
+ catName = "悬疑";
+ break;
+ }
+ case 0: {
+ catName = "动漫";
+ break;
+ }
+ default: {
+ break;
+ }
+
+
+ }
+ return catName;
+
+ }
+
+ public void sendBullet(Long contentId, String bullet) {
+
+ ScreenBullet screenBullet = new ScreenBullet();
+ screenBullet.setContentId(contentId);
+ screenBullet.setScreenBullet(bullet);
+ screenBullet.setCreateTime(new Date());
+
+ screenBulletMapper.insertSelective(screenBullet);
+ }
+
+ public List queryBullet(Long contentId) {
+
+ ScreenBulletExample example = new ScreenBulletExample();
+ example.createCriteria().andContentIdEqualTo(contentId);
+ example.setOrderByClause("create_time asc");
+
+ return screenBulletMapper.selectByExample(example);
+ }
+
+ public String queryIndexList(Long bookId, int count) {
+
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumEqualTo(count);
+ return bookIndexMapper.selectByExample(example).get(0).getIndexName();
+ }
+
+ public String queryContentList(Long bookId, int count) {
+ BookContentExample example = new BookContentExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumEqualTo(count);
+ return bookContentMapper.selectByExample(example).get(0).getContent();
+ }
+
+ public int countIndex(Long bookId) {
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId);
+ return bookIndexMapper.countByExample(example);
+ }
+
+ public List queryNewstBookIdList() {
+ return bookMapper.queryNewstBookIdList();
+ }
+
+ public List queryEndBookIdList() {
+ return bookMapper.queryEndBookIdList();
+ }
+
+
+ private void sendNewstBook(Long bookId) {
+ if (bookId >= 0) {
+
+ //List idList = queryEndBookIdList();
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.TEXT_PLAIN);
+ //headers.add("User-Agent","curl/7.12.1");
+ headers.add("Host", "data.zz.baidu.com");
+
+ String reqBody = "";
+ reqBody += ("https://www.zinglizingli.xyz/book/" + bookId + ".html" + "\n");
+ //reqBody += ("http://www.zinglizingli.xyz/book/" + bookId + ".html" + "\n");
+ headers.setContentLength(reqBody.length());
+ HttpEntity request = new HttpEntity<>(reqBody, headers);
+ System.out.println("推送数据:" + reqBody);
+ ResponseEntity stringResponseEntity = restTemplate.postForEntity("http://data.zz.baidu.com/urls?site=www.zinglizingli.xyz&token=IuK7oVrPKe3U606x", request, String.class);
+ System.out.println("推送URL结果:code:" + stringResponseEntity.getStatusCode().value() + ",body:" + stringResponseEntity.getBody());
+ }
+ }
+
+
+ private void sendNewstIndex(BookIndex bookIndex) {
+ if (bookIndex != null) {
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.TEXT_PLAIN);
+ //headers.add("User-Agent","curl/7.12.1");
+ headers.add("Host", "data.zz.baidu.com");
+
+ String reqBody = "";
+
+ //目录只推送最新一条
+ reqBody += ("https://www.zinglizingli.xyz/book/" + bookIndex.getBookId() + "/" + bookIndex.getIndexNum() + ".html" + "\n");
+ //reqBody += ("http://www.zinglizingli.xyz/book/" + index.getBookId() + "/" + index.getIndexNum() + ".html" + "\n");
+ headers.setContentLength(reqBody.length());
+ HttpEntity request = new HttpEntity<>(reqBody, headers);
+ System.out.println("推送数据:" + reqBody);
+ ResponseEntity stringResponseEntity = restTemplate.postForEntity("http://data.zz.baidu.com/urls?site=www.zinglizingli.xyz&token=IuK7oVrPKe3U606x", request, String.class);
+ System.out.println("推送URL结果:code:" + stringResponseEntity.getStatusCode().value() + ",body:" + stringResponseEntity.getBody());
+
+ }
+
+
+ }
+
+ public List queryPreAndNextIndexNum(Long bookId, Integer indexNum) {
+ List result = new ArrayList<>();
+ BookIndexExample example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumGreaterThan(indexNum);
+ example.setOrderByClause("index_num asc");
+ List bookIndices = bookIndexMapper.selectByExample(example);
+ if(bookIndices.size()>0){
+ result.add(bookIndices.get(0).getIndexNum());
+ }else{
+ result.add(indexNum);
+ }
+ example = new BookIndexExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andIndexNumLessThan(indexNum);
+ example.setOrderByClause("index_num DESC");
+ bookIndices = bookIndexMapper.selectByExample(example);
+ if(bookIndices.size()>0){
+ result.add(bookIndices.get(0).getIndexNum());
+ }else{
+ result.add(indexNum);
+ }
+ return result;
+
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/books/service/MailService.java b/src/main/java/xyz/zinglizingli/books/service/MailService.java
new file mode 100644
index 0000000..64af2e9
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/service/MailService.java
@@ -0,0 +1,113 @@
+package xyz.zinglizingli.books.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Service;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+@Service
+public class MailService {
+
+ private final Logger logger = LoggerFactory.getLogger(MailService.class);
+
+ @Value("${spring.mail.username}")
+ //使用@Value注入application.properties中指定的用户名
+ private String from;
+
+ String nickName = "精品小说楼";
+
+ @Autowired
+ //用于发送文件
+ private JavaMailSender mailSender;
+
+
+ public void sendSimpleMail(String to, String subject, String content) {
+
+ SimpleMailMessage message = new SimpleMailMessage();
+ message.setTo(to);//收信人
+ message.setSubject(subject);//主题
+ message.setText(content);//内容
+ message.setFrom(from);//发信人
+
+ mailSender.send(message);
+ }
+
+
+ public void sendHtmlMail(String to, String subject, String content){
+
+ logger.info("发送HTML邮件开始:{},{},{}", to, subject, content);
+ //使用MimeMessage,MIME协议
+ MimeMessage message = mailSender.createMimeMessage();
+
+ MimeMessageHelper helper;
+ //MimeMessageHelper帮助我们设置更丰富的内容
+ try {
+ helper = new MimeMessageHelper(message, true);
+ helper.setFrom(new InternetAddress(from, nickName, "UTF-8"));
+ helper.setTo(to);
+ helper.setSubject(subject);
+ helper.setText(content, true);//true代表支持html
+ mailSender.send(message);
+ logger.info("发送HTMLto"+to+"邮件成功");
+ } catch (Exception e) {
+ logger.error("发送HTML邮件失败:", e);
+ }
+ }
+
+ public void sendAttachmentMail(String to, String subject, String content, String filePath) {
+
+ logger.info("发送带附件邮件开始:{},{},{},{}", to, subject, content, filePath);
+ MimeMessage message = mailSender.createMimeMessage();
+
+ MimeMessageHelper helper;
+ try {
+ helper = new MimeMessageHelper(message, true);
+ //true代表支持多组件,如附件,图片等
+ helper.setFrom(from);
+ helper.setTo(to);
+ helper.setSubject(subject);
+ helper.setText(content, true);
+ FileSystemResource file = new FileSystemResource(new File(filePath));
+ String fileName = file.getFilename();
+ helper.addAttachment(fileName, file);//添加附件,可多次调用该方法添加多个附件
+ mailSender.send(message);
+ logger.info("发送带附件邮件成功");
+ } catch (MessagingException e) {
+ logger.error("发送带附件邮件失败", e);
+ }
+
+
+ }
+
+ public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) {
+
+ logger.info("发送带图片邮件开始:{},{},{},{},{}", to, subject, content, rscPath, rscId);
+ MimeMessage message = mailSender.createMimeMessage();
+
+ MimeMessageHelper helper;
+ try {
+ helper = new MimeMessageHelper(message, true);
+ helper.setFrom(new InternetAddress(from, nickName, "UTF-8"));
+ helper.setTo(to);
+ helper.setSubject(subject);
+ helper.setText(content, true);
+ FileSystemResource res = new FileSystemResource(new File(rscPath));
+ helper.addInline(rscId, res);//重复使用添加多个图片
+ mailSender.send(message);
+ logger.info("发送带图片邮件成功");
+ } catch (Exception e) {
+ logger.error("发送带图片邮件失败", e);
+ }
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/books/service/UserService.java b/src/main/java/xyz/zinglizingli/books/service/UserService.java
new file mode 100644
index 0000000..2444318
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/service/UserService.java
@@ -0,0 +1,86 @@
+package xyz.zinglizingli.books.service;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import xyz.zinglizingli.books.mapper.UserMapper;
+import xyz.zinglizingli.books.mapper.UserRefBookMapper;
+import xyz.zinglizingli.books.po.User;
+import xyz.zinglizingli.books.po.UserExample;
+import xyz.zinglizingli.books.po.UserRefBook;
+import xyz.zinglizingli.books.po.UserRefBookExample;
+import xyz.zinglizingli.books.util.MD5Util;
+
+import java.util.List;
+
+@Service
+public class UserService {
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Autowired
+ private UserRefBookMapper userRefBookMapper;
+
+
+ public boolean isExistLoginName(String loginName) {
+ UserExample example = new UserExample();
+ example.createCriteria().andLoginNameEqualTo(loginName);
+ return userMapper.countByExample(example)>0?true:false;
+ }
+
+ public void regist(User user) {
+ user.setPassword(MD5Util.MD5Encode(user.getPassword(),"utf-8"));
+ userMapper.insertSelective(user);
+ }
+
+ public void login(User user) {
+ UserExample example = new UserExample();
+ example.createCriteria().andLoginNameEqualTo(user.getLoginName())
+ .andPasswordEqualTo(MD5Util.MD5Encode(user.getPassword(),"utf-8"));
+ List users = userMapper.selectByExample(example);
+ if(users.size() > 0){
+ user.setId(users.get(0).getId());
+ }else {
+ user.setId(null);
+ }
+
+
+ }
+
+ public void addToCollect(Long bookId, long userId) {
+ UserRefBook userRefBook = new UserRefBook();
+ userRefBook.setBookId(bookId);
+ userRefBook.setUserId(userId);
+ UserRefBookExample example = new UserRefBookExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andUserIdEqualTo(userId);
+ userRefBookMapper.deleteByExample(example);
+ userRefBookMapper.insertSelective(userRefBook);
+
+ }
+
+ public boolean isCollect(Long bookId, long userId) {
+
+ UserRefBookExample example = new UserRefBookExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andUserIdEqualTo(userId);
+ return userRefBookMapper.countByExample(example)>0?true:false;
+
+ }
+
+ public void cancelToCollect(Long bookId, long userId) {
+ UserRefBookExample example = new UserRefBookExample();
+ example.createCriteria().andBookIdEqualTo(bookId).andUserIdEqualTo(userId);
+ userRefBookMapper.deleteByExample(example);
+ }
+
+ public void collectOrCancelBook(Long userid, Long bookId) {
+
+ boolean collect = isCollect(bookId, userid);
+
+ if(collect){
+ cancelToCollect(bookId, userid);;
+ }else{
+ addToCollect(bookId, userid);
+ }
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/books/util/ExcutorUtils.java b/src/main/java/xyz/zinglizingli/books/util/ExcutorUtils.java
new file mode 100644
index 0000000..5e40951
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/util/ExcutorUtils.java
@@ -0,0 +1,20 @@
+package xyz.zinglizingli.books.util;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ExcutorUtils {
+
+ private static ExecutorService fixedThreadPool;
+ private static ExecutorService cachedThreadPool ;
+ static{
+ fixedThreadPool = Executors.newFixedThreadPool(5);
+ cachedThreadPool = Executors.newCachedThreadPool();
+ }
+ public static void excuteFixedTask(Runnable task){
+ fixedThreadPool.execute(task);
+ }
+ public static void excuteCachedTask(Runnable task){
+ cachedThreadPool.execute(task);
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/books/util/MD5Util.java b/src/main/java/xyz/zinglizingli/books/util/MD5Util.java
new file mode 100644
index 0000000..cb0ea59
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/util/MD5Util.java
@@ -0,0 +1,39 @@
+package xyz.zinglizingli.books.util;
+
+import java.security.MessageDigest;
+
+public class MD5Util {
+ private static String byteArrayToHexString(byte b[]) {
+ StringBuffer resultSb = new StringBuffer();
+ for (int i = 0; i < b.length; i++)
+ resultSb.append(byteToHexString(b[i]));
+
+ return resultSb.toString();
+ }
+
+ private static String byteToHexString(byte b) {
+ int n = b;
+ if (n < 0)
+ n += 256;
+ int d1 = n / 16;
+ int d2 = n % 16;
+ return hexDigits[d1] + hexDigits[d2];
+ }
+
+ public static String MD5Encode(String origin, String charsetname) {
+ String resultString = null;
+ try {
+ resultString = new String(origin);
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ if (charsetname == null || "".equals(charsetname))
+ resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
+ else
+ resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
+ } catch (Exception exception) {
+ }
+ return resultString;
+ }
+
+ private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
+ "e", "f" };
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/zinglizingli/books/util/RandomValueUtil.java b/src/main/java/xyz/zinglizingli/books/util/RandomValueUtil.java
new file mode 100644
index 0000000..7ab1ced
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/util/RandomValueUtil.java
@@ -0,0 +1,152 @@
+package xyz.zinglizingli.books.util;
+
+
+
+
+/****
+ *
+ * Project Name:recruit-helper-util
+ * 随机数生成工具类,主要包括
+ * 中文姓名,性别,Email,手机号,住址
+ * @ClassName: RandomValueUtil
+ * @date 2018年5月23日 下午2:11:12
+ *
+ * @version 1.0
+ * @since
+ */
+public class RandomValueUtil {
+
+ //public static String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+ public static String base = "0123456789";
+ private static String firstName="赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计伏成戴谈宋茅庞熊纪舒屈项祝董梁杜阮蓝闵席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田樊胡凌霍虞万支柯咎管卢莫经房裘缪干解应宗宣丁贲邓郁单杭洪包诸左石崔吉钮龚程嵇邢滑裴陆荣翁荀羊於惠甄魏加封芮羿储靳汲邴糜松井段富巫乌焦巴弓牧隗山谷车侯宓蓬全郗班仰秋仲伊宫宁仇栾暴甘钭厉戎祖武符刘姜詹束龙叶幸司韶郜黎蓟薄印宿白怀蒲台从鄂索咸籍赖卓蔺屠蒙池乔阴郁胥能苍双闻莘党翟谭贡劳逄姬申扶堵冉宰郦雍却璩桑桂濮牛寿通边扈燕冀郏浦尚农温别庄晏柴瞿阎充慕连茹习宦艾鱼容向古易慎戈廖庚终暨居衡步都耿满弘匡国文寇广禄阙东殴殳沃利蔚越夔隆师巩厍聂晁勾敖融冷訾辛阚那简饶空曾毋沙乜养鞠须丰巢关蒯相查后江红游竺权逯盖益桓公万俟司马上官欧阳夏侯诸葛闻人东方赫连皇甫尉迟公羊澹台公冶宗政濮阳淳于仲孙太叔申屠公孙乐正轩辕令狐钟离闾丘长孙慕容鲜于宇文司徒司空亓官司寇仉督子车颛孙端木巫马公西漆雕乐正壤驷公良拓拔夹谷宰父谷粱晋楚阎法汝鄢涂钦段干百里东郭南门呼延归海羊舌微生岳帅缑亢况后有琴梁丘左丘东门西门商牟佘佴伯赏南宫墨哈谯笪年爱阳佟第五言福百家姓续";
+ private static String girl="秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊兰凤洁梅琳素云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜可姬舒影荔枝思丽 ";
+ public static String boy="伟刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘";
+ //public static final String[] email_suffix="@gmail.com,@yahoo.com,@msn.com,@hotmail.com,@aol.com,@ask.com,@live.com,@qq.com,@0355.net,@163.com,@163.net,@263.net,@3721.net,@yeah.net,@googlemail.com,@126.com,@sina.com,@sohu.com,@yahoo.com.cn".split(",");
+ public static final String[] email_suffix="@126.com,@163.com,@139.com,@sina.com,@aliyun.com,@189.cn,@sohu.com,@qq.com,@sogou.com".split(",");
+ public static int getNum(int start,int end) {
+ return (int)(Math.random()*(end-start+1)+start);
+ }
+
+ /***
+ *
+ * Project Name: recruit-helper-util
+ *
随机生成Email
+ *
+ * @date 2018年5月23日 下午2:13:06
+ * @version v1.0
+ * @since
+ * @param lMin
+ * 最小长度
+ * @param lMax
+ * 最大长度
+ * @return
+ */
+ public static String getEmail(int lMin,int lMax) {
+ int length=getNum(lMin,lMax);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ int number = (int)(Math.random()*base.length());
+ sb.append(base.charAt(number));
+ }
+ sb.append(email_suffix[(int)(Math.random()*email_suffix.length)]);
+ return sb.toString();
+ }
+
+ public static String getEmail() {
+ String emailTail = email_suffix[(int)(Math.random()*email_suffix.length)];
+ StringBuffer sb = new StringBuffer();
+ if(emailTail.equals("@qq.com")) {
+ int length = getNum(6, 10);
+ for (int i = 0; i < length; i++) {
+ int number = (int) (Math.random() * base.length());
+ sb.append(base.charAt(number));
+ }
+ }else{
+ sb.append(getTelephone());
+ }
+ sb.append(emailTail);
+ return sb.toString();
+ }
+
+ private static String[] telFirst="134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153".split(",");
+
+ /***
+ *
+ * Project Name: recruit-helper-util
+ *
随机生成手机号码
+ *
+ * @date 2018年5月23日 下午2:14:17
+ * @version v1.0
+ * @since
+ * @return
+ */
+ public static String getTelephone() {
+ int index=getNum(0,telFirst.length-1);
+ String first=telFirst[index];
+ String second=String.valueOf(getNum(1,888)+10000).substring(1);
+ String thrid=String.valueOf(getNum(1,9100)+10000).substring(1);
+ return first+second+thrid;
+ }
+
+ /***
+ *
+ * Project Name: recruit-helper-util
+ *
随机生成8位电话号码
+ *
+ * @date 2018年5月23日 下午2:15:31
+ * @version v1.0
+ * @since
+ * @return
+ */
+ public static String getLandline() {
+ int index=getNum(0,telFirst.length-1);
+ String first=telFirst[index];
+ String second=String.valueOf(getNum(1,888)+10000).substring(1);
+ String thrid=String.valueOf(getNum(1,9100)+10000).substring(1);
+ return first+second+thrid;
+ }
+
+
+
+ /**
+ * 返回中文姓名
+ */
+ public static String name_sex = "";
+
+ /***
+ *
+ * Project Name: recruit-helper-util
+ *
返回中文姓名
+ *
+ * @date 2018年5月23日 下午2:16:16
+ * @version v1.0
+ * @since
+ * @return
+ */
+ public static String getChineseName() {
+ int index = getNum(0, firstName.length() - 1);
+ String first = firstName.substring(index, index + 1);
+ int sex = getNum(0, 1);
+ String str = boy;
+ int length = boy.length();
+ if (sex == 0) {
+ str = girl;
+ length = girl.length();
+ name_sex = "女";
+ } else {
+ name_sex = "男";
+ }
+ index = getNum(0, length - 1);
+ String second = str.substring(index, index + 1);
+ int hasThird = getNum(0, 1);
+ String third = "";
+ if (hasThird == 1) {
+ index = getNum(0, length - 1);
+ third = str.substring(index, index + 1);
+ }
+ return first + second + third;
+ }
+
+
+}
+
diff --git a/src/main/java/xyz/zinglizingli/books/util/UUIDUtils.java b/src/main/java/xyz/zinglizingli/books/util/UUIDUtils.java
new file mode 100644
index 0000000..103fcd9
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/util/UUIDUtils.java
@@ -0,0 +1,93 @@
+package xyz.zinglizingli.books.util;
+
+import java.util.UUID;
+
+public class UUIDUtils {
+
+ public static final String[] CHARS = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
+ "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6",
+ "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
+ "S", "T", "U", "V", "W", "X", "Y", "Z" };
+
+ /**
+ * 生成指定长度的uuid
+ *
+ * @param length
+ * @return
+ */
+ private static String getUUID(int length, UUID uuid) {
+ int groupLength = 32 / length;
+ StringBuilder sb = new StringBuilder();
+ String id = uuid.toString().replace("-", "");
+ for (int i = 0; i < length; i++) {
+ String str = id.substring(i * groupLength, i * groupLength + groupLength);
+ int x = Integer.parseInt(str, 16);
+ sb.append(CHARS[x % 0x3E]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 8位UUID
+ *
+ * @return
+ */
+ public static String getUUID8() {
+ return getUUID(8, UUID.randomUUID());
+ }
+
+ /**
+ * 8位UUID
+ *
+ * @return
+ */
+ public static String getUUID8(byte[] bytes) {
+ return getUUID(8, UUID.nameUUIDFromBytes(bytes));
+ }
+
+ /**
+ * 8位UUID
+ *
+ * @return
+ */
+ public static String getUUID8(String fromString) {
+ return getUUID(8, UUID.fromString(fromString));
+ }
+
+ /**
+ * 16位UUID
+ *
+ * @return
+ */
+ public static String getUUID16() {
+ return getUUID(16, UUID.randomUUID());
+ }
+
+ /**
+ * 16位UUID
+ *
+ * @return
+ */
+ public static String getUUID16(String fromString) {
+ return getUUID(16, UUID.fromString(fromString));
+ }
+
+ /**
+ * 16位UUID
+ *
+ * @return
+ */
+ public static String getUUID16(byte[] bytes) {
+ return getUUID(16, UUID.nameUUIDFromBytes(bytes));
+ }
+
+ /**
+ * 32位UUID
+ *
+ * @return
+ */
+ public static String getUUID32() {
+ return UUID.randomUUID().toString().replace("-", "");
+ }
+
+}
diff --git a/src/main/java/xyz/zinglizingli/books/vo/BookVO.java b/src/main/java/xyz/zinglizingli/books/vo/BookVO.java
new file mode 100644
index 0000000..4536c16
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/vo/BookVO.java
@@ -0,0 +1,16 @@
+package xyz.zinglizingli.books.vo;
+
+import xyz.zinglizingli.books.po.Book;
+
+public class BookVO extends Book {
+
+ private String cateName;
+
+ public String getCateName() {
+ return cateName;
+ }
+
+ public void setCateName(String cateName) {
+ this.cateName = cateName;
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/books/web/ApiBookController.java b/src/main/java/xyz/zinglizingli/books/web/ApiBookController.java
new file mode 100644
index 0000000..f1fca0f
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/web/ApiBookController.java
@@ -0,0 +1,187 @@
+package xyz.zinglizingli.books.web;
+
+
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.po.BookContent;
+import xyz.zinglizingli.books.po.BookIndex;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.books.vo.BookVO;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
+
+@RestController
+@RequestMapping("api/book")
+public class ApiBookController {
+
+
+ @Autowired
+ private BookService bookService;
+
+ @Autowired
+ private CommonCacheUtil commonCacheUtil;
+
+
+ @RequestMapping("hotBook")
+ public List hotBooks () {
+ //查询热点数据
+ List hotBooks = bookService.search(1, 6, null, null, null, null, null, null, null, "visit_count DESC,score ", "DESC");
+ return hotBooks;
+ }
+
+ @RequestMapping("newstBook")
+ public List newstBook() {
+ //查询最近更新数据
+ List newBooks = bookService.search(1, 6, null, null, null, null, null, null, null, "update_time", "DESC");
+
+ return newBooks;
+ }
+
+ @RequestMapping("search")
+ public Map search(@RequestParam(value = "curr", defaultValue = "1") int page, @RequestParam(value = "limit", defaultValue = "20") int pageSize,
+ @RequestParam(value = "keyword", required = false) String keyword,
+ @RequestParam(value = "bookStatus", required = false) String bookStatus,
+ @RequestParam(value = "catId", required = false) Integer catId,
+ @RequestParam(value = "historyBookIds", required = false) String ids,
+ @RequestParam(value = "token", required = false) String token,
+ @RequestParam(value = "sortBy", defaultValue = "update_time") String sortBy, @RequestParam(value = "sort", defaultValue = "DESC") String sort,
+ HttpServletRequest req, HttpServletResponse resp) {
+
+ Map modelMap = new HashMap<>();
+ String userId = null;
+ String titleType = "最近更新";
+ if (catId != null) {
+ titleType = bookService.getCatNameById(catId);
+ ;
+ } else if (keyword != null) {
+ titleType = "搜索";
+ } else if ("score".equals(sortBy)) {
+ titleType = "小说排行榜";
+ } else if (ids != null) {
+ titleType = "阅读记录";
+ } else if (token != null) {
+ userId = commonCacheUtil.get(token);
+ titleType = "我的书架";
+ }
+ modelMap.put("titleType", titleType);
+ List books = bookService.search(page, pageSize, userId, ids, keyword,bookStatus, catId, null, null, sortBy, sort);
+ List bookVOList;
+ if (StringUtils.isEmpty(ids)) {
+ bookVOList = new ArrayList<>();
+ for (Book book : books) {
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ bookVOList.add(bookvo);
+ }
+
+ } else {
+ if (!ids.contains("-")) {
+ List idsArr = Arrays.asList(ids.split(","));
+ int length = idsArr.size();
+ BookVO[] bookVOArr = new BookVO[length];
+ for (Book book : books) {
+ int index = idsArr.indexOf(book.getId() + "");
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ bookVOArr[length - index - 1] = bookvo;
+ }
+ bookVOList = Arrays.asList(bookVOArr);
+ } else {
+ bookVOList = new ArrayList<>();
+ }
+
+ }
+
+ PageInfo bookPageInfo = new PageInfo<>(books);
+ modelMap.put("limit", bookPageInfo.getPageSize());
+ modelMap.put("curr", bookPageInfo.getPageNum());
+ modelMap.put("total", bookPageInfo.getTotal());
+ modelMap.put("books", bookVOList);
+ modelMap.put("ids", ids);
+ modelMap.put("keyword", keyword);
+ modelMap.put("catId", catId);
+ modelMap.put("sortBy", sortBy);
+ modelMap.put("sort", sort);
+ return modelMap;
+ }
+
+ @RequestMapping("{bookId}.html")
+ public Map detail(@PathVariable("bookId") Long bookId) {
+ Map modelMap = new HashMap<>();
+ //查询基本信息
+ Book book = bookService.queryBaseInfo(bookId);
+ //查询最新目录信息
+ List indexList = bookService.queryNewIndexList(bookId);
+
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ modelMap.put("bookId", bookId);
+ modelMap.put("book", bookvo);
+ modelMap.put("indexList", indexList);
+ return modelMap;
+ }
+
+ @RequestMapping("{bookId}/index.html")
+ public Map bookIndex(@PathVariable("bookId") Long bookId) {
+ Map modelMap = new HashMap<>();
+ List indexList = bookService.queryAllIndexList(bookId);
+ String bookName = bookService.queryBaseInfo(bookId).getBookName();
+ modelMap.put("indexList", indexList);
+ modelMap.put("bookName", bookName);
+ modelMap.put("bookId", bookId);
+ return modelMap;
+ }
+
+ @RequestMapping("{bookId}/{indexNum}.html")
+ public Map bookContent(@PathVariable("bookId") Long bookId, @PathVariable("indexNum") Integer indexNum) {
+ Map modelMap = new HashMap<>();
+ //查询最大章节号
+ List maxAndMinIndexNum = bookService.queryMaxAndMinIndexNum(bookId);
+ if(maxAndMinIndexNum.size()>0) {
+ int maxIndexNum = maxAndMinIndexNum.get(0);
+ int minIndexNum = maxAndMinIndexNum.get(1);
+ if (indexNum < minIndexNum) {
+ indexNum = maxIndexNum;
+ }
+ if (indexNum > maxIndexNum) {
+ indexNum = minIndexNum;
+ }
+ }
+ BookContent bookContent = bookService.queryBookContent(bookId, indexNum);
+ String indexName;
+ if(bookContent==null) {
+ bookContent = new BookContent();
+ bookContent.setId(-1l);
+ bookContent.setBookId(bookId);
+ bookContent.setIndexNum(indexNum);
+ bookContent.setContent("正在手打中,请稍等片刻,内容更新后,需要重新刷新页面,才能获取最新更新");
+ indexName="?";
+ }else{
+ indexName = bookService.queryIndexNameByBookIdAndIndexNum(bookId, indexNum);
+ }
+ modelMap.put("indexName", indexName);
+ String bookName = bookService.queryBaseInfo(bookId).getBookName();
+ modelMap.put("bookName", bookName);
+ return modelMap;
+ }
+
+ @RequestMapping("addVisit")
+ public String addVisit(@RequestParam("bookId") Long bookId) {
+
+ bookService.addVisitCount(bookId);
+
+ return "ok";
+ }
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/books/web/BookController.java b/src/main/java/xyz/zinglizingli/books/web/BookController.java
new file mode 100644
index 0000000..86168bf
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/web/BookController.java
@@ -0,0 +1,326 @@
+package xyz.zinglizingli.books.web;
+
+
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import xyz.zinglizingli.books.constant.CacheKeyConstans;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.po.BookContent;
+import xyz.zinglizingli.books.po.BookIndex;
+import xyz.zinglizingli.books.po.ScreenBullet;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.books.vo.BookVO;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.util.*;
+
+@Controller
+@RequestMapping("book")
+public class BookController {
+
+
+ @Autowired
+ private BookService bookService;
+
+ @Autowired
+ private CommonCacheUtil commonCacheUtil;
+
+
+ @RequestMapping("index.html")
+ public String index(ModelMap modelMap) {
+ List hotBooks = (List) commonCacheUtil.getObject(CacheKeyConstans.HOT_BOOK_LIST_KEY);
+ if (hotBooks == null) {
+ //查询热点数据
+ hotBooks = bookService.search(1, 9, null, null, null, null, null, null, null, "visit_count DESC,score ", "DESC");
+ commonCacheUtil.setObject(CacheKeyConstans.HOT_BOOK_LIST_KEY, hotBooks, 60 * 60 * 24);
+ }
+ List newBooks = (List) commonCacheUtil.getObject(CacheKeyConstans.NEWST_BOOK_LIST_KEY);
+ if (newBooks == null) {
+ //查询最近更新数据
+ newBooks = bookService.search(1, 20, null, null, null, null, null, null, null, "update_time", "DESC");
+ commonCacheUtil.setObject(CacheKeyConstans.NEWST_BOOK_LIST_KEY, newBooks, 60 * 30);
+ }
+ modelMap.put("hotBooks", hotBooks);
+ modelMap.put("newBooks", newBooks);
+ return "books/index";
+ }
+
+ @RequestMapping("search")
+ public String search(@RequestParam(value = "curr", defaultValue = "1") int page, @RequestParam(value = "limit", defaultValue = "20") int pageSize,
+ @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "catId", required = false) Integer catId,
+ @RequestParam(value = "historyBookIds", required = false) String ids,
+ @RequestParam(value = "bookStatus", required = false) String bookStatus,
+ @RequestParam(value = "token", required = false) String token,
+ @RequestParam(value = "sortBy", defaultValue = "update_time") String sortBy, @RequestParam(value = "sort", defaultValue = "DESC") String sort,
+ HttpServletRequest req, HttpServletResponse resp, ModelMap modelMap) {
+
+ String userId = null;
+ String titleType = "最近更新";
+ if (catId != null) {
+ titleType = bookService.getCatNameById(catId) + "分类频道";
+ ;
+ } else if ("score".equals(sortBy)) {
+ titleType = "小说排行";
+ } else if (ids != null) {
+ titleType = "阅读记录";
+ } else if (token != null) {
+ userId = commonCacheUtil.get(token);
+ titleType = "我的书架";
+ } else if (bookStatus != null && bookStatus.contains("完成")) {
+ titleType = "完本小说";
+ } else if (keyword != null) {
+ titleType = "搜索";
+ }
+ modelMap.put("titleType", titleType);
+ List books;
+ List bookVOList;
+ if (StringUtils.isEmpty(ids) || !StringUtils.isEmpty(keyword)) {
+ books = bookService.search(page, pageSize, userId, ids, keyword, bookStatus, catId, null, null, sortBy, sort);
+ bookVOList = new ArrayList<>();
+ for (Book book : books) {
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ bookVOList.add(bookvo);
+ }
+
+ } else {
+ if (!ids.contains("-")) {
+ books = bookService.search(page, 50, userId, ids, keyword, null, catId, null, null, sortBy, sort);
+ List idsArr = Arrays.asList(ids.split(","));
+ int length = idsArr.size();
+ BookVO[] bookVOArr = new BookVO[books.size()];
+ for (Book book : books) {
+ int index = idsArr.indexOf(book.getId() + "");
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ bookVOArr[books.size() - index - 1] = bookvo;
+ }
+ bookVOList = Arrays.asList(bookVOArr);
+ } else {
+ books = new ArrayList<>();
+ bookVOList = new ArrayList<>();
+ }
+
+ }
+
+ PageInfo bookPageInfo = new PageInfo<>(books);
+ modelMap.put("limit", bookPageInfo.getPageSize());
+ modelMap.put("curr", bookPageInfo.getPageNum());
+ modelMap.put("total", bookPageInfo.getTotal());
+ modelMap.put("books", bookVOList);
+ modelMap.put("ids", ids);
+ modelMap.put("token", token);
+ modelMap.put("bookStatus", bookStatus);
+ modelMap.put("keyword", keyword);
+ modelMap.put("catId", catId);
+ modelMap.put("sortBy", sortBy);
+ modelMap.put("sort", sort);
+ return "books/book_search";
+ }
+
+
+ @RequestMapping("searchSoftBook.html")
+ public String searchSoftBook(@RequestParam(value = "curr", defaultValue = "1") int page, @RequestParam(value = "limit", defaultValue = "20") int pageSize,
+ @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "catId", defaultValue = "8") Integer catId,
+ @RequestParam(value = "softCat", required = false) Integer softCat,
+ @RequestParam(value = "bookStatus", required = false) String bookStatus,
+ @RequestParam(value = "softTag", required = false) String softTag,
+ @RequestParam(value = "sortBy", defaultValue = "update_time") String sortBy, @RequestParam(value = "sort", defaultValue = "DESC") String sort,
+ HttpServletRequest req, HttpServletResponse resp, ModelMap modelMap) {
+
+ String userId = null;
+ List books = bookService.search(page, pageSize, userId, null, keyword, bookStatus, catId, softCat, softTag, sortBy, sort);
+ List bookVOList;
+ bookVOList = new ArrayList<>();
+ for (Book book : books) {
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getSoftCatNameById(bookvo.getSoftCat()));
+ bookVOList.add(bookvo);
+ }
+
+
+ PageInfo bookPageInfo = new PageInfo<>(books);
+ modelMap.put("limit", bookPageInfo.getPageSize());
+ modelMap.put("curr", bookPageInfo.getPageNum());
+ modelMap.put("total", bookPageInfo.getTotal());
+ modelMap.put("books", bookVOList);
+ modelMap.put("keyword", keyword);
+ modelMap.put("bookStatus", bookStatus);
+ modelMap.put("softCat", softCat);
+ modelMap.put("softTag", softTag);
+ modelMap.put("sortBy", sortBy);
+ modelMap.put("sort", sort);
+ return "books/soft_book_search";
+ }
+
+ @RequestMapping("{bookId}.html")
+ public String detail(@PathVariable("bookId") Long bookId, ModelMap modelMap) {
+ //查询基本信息
+ Book book = bookService.queryBaseInfo(bookId);
+ //查询最新目录信息
+ List indexList = bookService.queryNewIndexList(bookId);
+
+ int minIndexNum = 0;
+ //查询最小目录号
+ List integers = bookService.queryMaxAndMinIndexNum(bookId);
+ if(integers.size()>1){
+ minIndexNum = integers.get(1);
+ }
+
+ BookVO bookvo = new BookVO();
+ BeanUtils.copyProperties(book, bookvo);
+ bookvo.setCateName(bookService.getCatNameById(bookvo.getCatid()));
+ modelMap.put("bookId", bookId);
+ modelMap.put("book", bookvo);
+ modelMap.put("minIndexNum", minIndexNum);
+ modelMap.put("indexList", indexList);
+ if (indexList != null && indexList.size() > 0) {
+ modelMap.put("lastIndexName", indexList.get(0).getIndexName());
+ modelMap.put("lastIndexNum", indexList.get(0).getIndexNum());
+ }
+ return "books/book_detail";
+ }
+
+ @RequestMapping("{bookId}/index.html")
+ public String bookIndex(@PathVariable("bookId") Long bookId, ModelMap modelMap) {
+ List indexList = bookService.queryAllIndexList(bookId);
+ String bookName = bookService.queryBaseInfo(bookId).getBookName();
+ modelMap.put("indexList", indexList);
+ modelMap.put("bookName", bookName);
+ modelMap.put("bookId", bookId);
+ return "books/book_index";
+ }
+
+ @RequestMapping("{bookId}/{indexNum}.html")
+ public String bookContent(@PathVariable("bookId") Long bookId, @PathVariable("indexNum") Integer indexNum, ModelMap modelMap) {
+ BookContent bookContent = bookService.queryBookContent(bookId, indexNum);
+ String indexName;
+ if(bookContent==null) {
+ bookContent = new BookContent();
+ bookContent.setId(-1l);
+ bookContent.setBookId(bookId);
+ bookContent.setIndexNum(indexNum);
+ bookContent.setContent("正在手打中,请稍等片刻,内容更新后,需要重新刷新页面,才能获取最新更新");
+ indexName="更新中。。。";
+ }else{
+ indexName = bookService.queryIndexNameByBookIdAndIndexNum(bookId, indexNum);
+ }
+ List preAndNextIndexNum = bookService.queryPreAndNextIndexNum(bookId,indexNum);
+ modelMap.put("nextIndexNum", preAndNextIndexNum.get(0));
+ modelMap.put("preIndexNum", preAndNextIndexNum.get(1));
+ modelMap.put("bookContent", bookContent);
+ modelMap.put("indexName", indexName);
+ String bookName = bookService.queryBaseInfo(bookId).getBookName();
+ modelMap.put("bookName", bookName);
+ return "books/book_content";
+ }
+
+ @RequestMapping("addVisit")
+ @ResponseBody
+ public String addVisit(@RequestParam("bookId") Long bookId) {
+
+ bookService.addVisitCount(bookId);
+
+ return "ok";
+ }
+
+ @RequestMapping("sendBullet")
+ @ResponseBody
+ public Map sendBullet(@RequestParam("contentId") Long contentId, @RequestParam("bullet") String bullet) {
+ Map result = new HashMap<>();
+ bookService.sendBullet(contentId, bullet);
+ result.put("code", 1);
+ result.put("desc", "ok");
+ return result;
+ }
+
+ @RequestMapping("queryIsDownloading")
+ @ResponseBody
+ public Map queryIsDownloading(HttpSession session) {
+ Map result = new HashMap<>();
+ if (session.getAttribute("isDownloading") != null) {
+ result.put("code", 1);
+ } else {
+ result.put("code", 0);
+ }
+ return result;
+ }
+
+
+ @RequestMapping("queryBullet")
+ @ResponseBody
+ public List queryBullet(@RequestParam("contentId") Long contentId) {
+
+ return bookService.queryBullet(contentId);
+ }
+
+
+ /**
+ * 文件下载
+ */
+ @RequestMapping(value = "/download")
+ public void download(@RequestParam("bookId") Long bookId, @RequestParam("bookName") String bookName, HttpServletResponse resp, HttpSession session) {
+ try {
+ session.setAttribute("isDownloading", 1);
+ int count = bookService.countIndex(bookId);
+
+
+ OutputStream out = resp.getOutputStream();
+ //设置响应头,对文件进行url编码
+ bookName = URLEncoder.encode(bookName, "UTF-8");
+ resp.setContentType("application/octet-stream");//解决手机端不能下载附件的问题
+ resp.setHeader("Content-Disposition", "attachment;filename=" + bookName + ".txt");
+ if (count > 0) {
+ for (int i = 0; i < count; i++) {
+ String index = bookService.queryIndexList(bookId, i);
+ String content = bookService.queryContentList(bookId, i);
+ out.write(index.getBytes("utf-8"));
+ out.write("\n".getBytes("utf-8"));
+ content = content.replaceAll(" ", "\r\n");
+ content = content.replaceAll(" ", " ");
+ content = content.replaceAll("]*>", "");
+ content = content.replaceAll(" ", "");
+ content = content.replaceAll("]*>", "");
+ content = content.replaceAll("
", "");
+ content = content.replaceAll("]*>[^<]*]*>[^<]* \\s*
", "");
+ content = content.replaceAll("]*>", "");
+ content = content.replaceAll("
", "\r\n");
+ out.write(content.getBytes("utf-8"));
+ out.write("\r\n".getBytes("utf-8"));
+ out.write("\r\n".getBytes("utf-8"));
+ out.flush();
+ }
+
+ }
+
+ out.close();
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ session.removeAttribute("isDownloading");
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/books/web/UserController.java b/src/main/java/xyz/zinglizingli/books/web/UserController.java
new file mode 100644
index 0000000..b37177f
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/books/web/UserController.java
@@ -0,0 +1,161 @@
+package xyz.zinglizingli.books.web;
+
+
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.po.BookContent;
+import xyz.zinglizingli.books.po.BookIndex;
+import xyz.zinglizingli.books.po.User;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.books.service.UserService;
+import xyz.zinglizingli.books.util.UUIDUtils;
+import xyz.zinglizingli.books.vo.BookVO;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+@Controller
+@RequestMapping("user")
+public class UserController {
+
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private BookService bookService;
+
+ @Autowired
+ private CommonCacheUtil commonCacheUtil;
+
+
+ @RequestMapping("login.html")
+ public String login(Long bookId, ModelMap modelMap) {
+ modelMap.put("bookId", bookId);
+ return "user/login";
+ }
+
+
+ @RequestMapping("loginOrRegist")
+ @ResponseBody
+ public Map loginOrRegist(User user,Long bookId) {
+ Map result = new HashMap<>();
+ //查询用户名是否存在
+ boolean isExistLoginName = userService.isExistLoginName(user.getLoginName());
+ String token = null;
+ if (isExistLoginName) {
+ //登录
+ userService.login(user);
+ if (user.getId() != null) {
+ token = UUIDUtils.getUUID32();
+ commonCacheUtil.set(token, user.getId() + "");
+ result.put("code", 1);
+ result.put("desc", "登录成功!");
+ if(!StringUtils.isEmpty(bookId)) {
+ userService.collectOrCancelBook(user.getId(), bookId);
+ }
+ } else {
+ result.put("code", -1);
+ result.put("desc", "用户名或密码错误!");
+ }
+ } else {
+ //注册
+ userService.regist(user);
+ Long userId = user.getId();
+ token = UUIDUtils.getUUID32();
+ commonCacheUtil.set(token, userId + "");
+ result.put("code", 2);
+ result.put("desc", "注册成功!");
+ if(!StringUtils.isEmpty(bookId)) {
+ userService.collectOrCancelBook(user.getId(), bookId);
+ }
+ }
+ if(token != null){
+ result.put("token",token);
+ }
+ return result;
+ }
+
+ @RequestMapping("isLogin")
+ @ResponseBody
+ public Map isLogin(String token) {
+ Map result = new HashMap<>();
+ String userId = commonCacheUtil.get(token);
+ if(StringUtils.isEmpty(userId)){
+ result.put("code", -1);
+ result.put("desc", "未登录!");
+ }else{
+ result.put("code", 1);
+ result.put("desc", "已登录!");
+ }
+ return result;
+ }
+
+
+ @RequestMapping("addToCollect")
+ @ResponseBody
+ public Map addToCollect(Long bookId,String token) {
+ Map result = new HashMap<>();
+ String userId = commonCacheUtil.get(token);
+ if(StringUtils.isEmpty(userId)){
+ result.put("code", -1);
+ result.put("desc", "未登录!");
+ }else {
+ userService.addToCollect(bookId,Long.parseLong(userId));
+ result.put("code", 1);
+ result.put("desc", "加入成功,请前往我的书架查看!");
+ }
+ return result;
+ }
+
+ @RequestMapping("cancelToCollect")
+ @ResponseBody
+ public Map cancelToCollect(Long bookId,String token) {
+ Map result = new HashMap<>();
+ String userId = commonCacheUtil.get(token);
+ if(StringUtils.isEmpty(userId)){
+ result.put("code", -1);
+ result.put("desc", "未登录!");
+ }else {
+ userService.cancelToCollect(bookId,Long.parseLong(userId));
+ result.put("code", 1);
+ result.put("desc", "撤下成功!");
+ }
+ return result;
+ }
+
+ @RequestMapping("isCollect")
+ @ResponseBody
+ public Map isCollect(Long bookId,String token) {
+ Map result = new HashMap<>();
+ String userId = commonCacheUtil.get(token);
+ if(StringUtils.isEmpty(userId)){
+ result.put("code", -1);
+ result.put("desc", "未登录!");
+ }else {
+ boolean isCollect = userService.isCollect(bookId,Long.parseLong(userId));
+ if(isCollect) {
+ result.put("code", 1);
+ result.put("desc", "已收藏!");
+ }else{
+ result.put("code", 2);
+ result.put("desc", "未收藏!");
+ }
+ }
+ return result;
+ }
+
+
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/cache/CommonCacheUtil.java b/src/main/java/xyz/zinglizingli/search/cache/CommonCacheUtil.java
new file mode 100644
index 0000000..9c712e9
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/cache/CommonCacheUtil.java
@@ -0,0 +1,56 @@
+package xyz.zinglizingli.search.cache;
+
+public interface CommonCacheUtil {
+
+ /**
+ * 根据key获取缓存的String类型数据
+ */
+ String get(String key);
+
+ /**
+ * 设置String类型的缓存
+ */
+ void set(String key, String value);
+
+ /**
+ * 设置一个有过期时间的String类型的缓存,单位秒
+ */
+ void set(String key, String value, long timeout);
+
+ /**
+ * 根据key获取缓存的Object类型数据
+ */
+ Object getObject(String key);
+
+ /**
+ * 设置Object类型的缓存
+ */
+ void setObject(String key, Object value);
+
+ /**
+ * 设置一个有过期时间的Object类型的缓存,单位秒
+ */
+ void setObject(String key, Object value, long timeout);
+
+ /**
+ * 根据key删除缓存的数据
+ */
+ void del(String key);
+
+
+ /**
+ * 判断是否存在一个key
+ * */
+ boolean contains(String key);
+
+ /**
+ * 设置key过期时间
+ * */
+ void expire(String key, long timeout);
+
+ /**
+ * 刷新缓存
+ * */
+ void refresh(String key);
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/cache/impl/EHCacheUtil.java b/src/main/java/xyz/zinglizingli/search/cache/impl/EHCacheUtil.java
new file mode 100644
index 0000000..ae41a61
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/cache/impl/EHCacheUtil.java
@@ -0,0 +1,150 @@
+package xyz.zinglizingli.search.cache.impl;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+
+@Service
+public class EHCacheUtil implements CommonCacheUtil {
+
+ @Autowired
+ private CacheManager cacheManager ;
+
+ private static final String CACHE_NAME = "utilCache";
+
+
+ /**
+ * 获得一个Cache,没有则创建一个。
+ * @param cacheName
+ * @return
+ */
+ private Cache getCache(){
+
+ /*Cache cache = cacheManager.getCache(cacheName);
+ if (cache == null){
+ cacheManager.addCache(cacheName);
+ cache = cacheManager.getCache(cacheName);
+ CacheConfiguration config = cache.getCacheConfiguration();
+ config.setEternal(false);
+ config.internalSetTimeToIdle(0);
+ config.internalSetTimeToIdle(0);
+ }*/
+ Cache cache = cacheManager.getCache("util_cache");
+ return cache;
+ }
+
+
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+
+
+
+
+ @Override
+ public String get(String key) {
+ Element element = getCache().get(key);
+ return element==null?null:(String)element.getObjectValue();
+ }
+
+ @Override
+ public void set(String key, String value) {
+ Element element = new Element(key, value);
+ Cache cache = getCache();
+ cache.getCacheConfiguration().setEternal(true);//不过期
+ cache.put(element);
+
+ }
+
+ @Override
+ public void set(String key, String value, long timeout) {
+ Element element = new Element(key, value);
+ element.setTimeToLive((int) timeout);
+ Cache cache = getCache();
+ cache.put(element);
+
+ }
+
+ @Override
+ public void del(String key) {
+ getCache().remove(key);
+
+
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return getCache().isKeyInCache(key);
+ }
+
+ @Override
+ public void expire(String key, long timeout) {
+ Element element = getCache().get(key);
+ if (element != null) {
+ Object value = element.getValue();
+ element = new Element(key, value);
+ element.setTimeToLive((int)timeout);
+ Cache cache = getCache();
+ cache.put(element);
+ }
+ }
+
+
+ /**
+ * 根据key获取缓存的Object类型数据
+ */
+ @Override
+ public Object getObject(String key) {
+ Element element = getCache().get(key);
+ return element==null?null:element.getObjectValue();
+ }
+
+
+ /**
+ * 设置Object类型的缓存
+ * @param
+ */
+ @Override
+ public void setObject(String key, Object value) {
+ Element element = new Element(key, value);
+ Cache cache = getCache();
+ cache.getCacheConfiguration().setEternal(true);//不过期
+ cache.put(element);
+
+ }
+
+
+ /**
+ * 设置一个有过期时间的Object类型的缓存,单位秒
+ */
+ @Override
+ public void setObject(String key, Object value, long timeout) {
+ Element element = new Element(key, value);
+ element.setTimeToLive((int) timeout);
+ Cache cache = getCache();
+ cache.put(element);
+
+ }
+
+
+ @Override
+ public void refresh(String key) {
+ Element element = getCache().get(key);
+ if (element != null) {
+ Object value = element.getValue();
+ int timeToLive = element.getTimeToLive();
+ element = new Element(key, value);
+ element.setTimeToLive(timeToLive);
+ Cache cache = getCache();
+ cache.put(element);
+ }
+
+ }
+
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/config/ErrorConfig.java b/src/main/java/xyz/zinglizingli/search/config/ErrorConfig.java
new file mode 100644
index 0000000..93527f8
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/config/ErrorConfig.java
@@ -0,0 +1,23 @@
+package xyz.zinglizingli.search.config;
+
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.server.ErrorPageRegistrar;
+import org.springframework.boot.web.server.ErrorPageRegistry;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+
+/**
+ *定义配置类
+ */
+@Configuration
+public class ErrorConfig implements ErrorPageRegistrar {
+
+ @Override
+ public void registerErrorPages(ErrorPageRegistry registry) {
+ ErrorPage[] errorPages = new ErrorPage[2];
+ errorPages[0] = new ErrorPage(HttpStatus.NOT_FOUND, "/book/index.html");
+ errorPages[1] = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/mang.html");
+
+ registry.addErrorPages(errorPages);
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/config/FilterConfig.java b/src/main/java/xyz/zinglizingli/search/config/FilterConfig.java
new file mode 100644
index 0000000..90b60f8
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/config/FilterConfig.java
@@ -0,0 +1,19 @@
+package xyz.zinglizingli.search.config;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import xyz.zinglizingli.search.filter.SearchFilter;
+
+@Configuration
+public class FilterConfig{
+
+ @Bean
+ public FilterRegistrationBean filterRegist() {
+ FilterRegistrationBean frBean = new FilterRegistrationBean();
+ frBean.setFilter(new SearchFilter());
+ frBean.addUrlPatterns("/*");
+ return frBean;
+ }
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/filter/SearchFilter.java b/src/main/java/xyz/zinglizingli/search/filter/SearchFilter.java
new file mode 100644
index 0000000..ab902f4
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/filter/SearchFilter.java
@@ -0,0 +1,664 @@
+package xyz.zinglizingli.search.filter;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.*;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RequestCallback;
+import org.springframework.web.client.RestTemplate;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+import xyz.zinglizingli.search.utils.SpringUtil;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SearchFilter implements Filter {
+
+ private static final Logger log = LoggerFactory.getLogger(SearchFilter.class);
+
+ private CommonCacheUtil cacheUtil;
+
+ private static List picPostFix;
+
+ private static List localFileFix;
+
+ private static List staticFileFix;
+
+ private static List noteURI;
+
+ private RestTemplate restTemplate;
+
+
+ private final String SUANWEI_BOOK_REGEX = "";
+ private final String SUANWEI_BOOK_HTML_REGEX = "/\\d+_\\d+\\.html";
+
+ private final String XIYANGYANG_BOOK_REGEX = " ";
+ private final String XIYANGYANG_BOOK_HTML_REGEX = "/\\d+_\\d+\\.html";
+
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ picPostFix = new ArrayList<>();
+ picPostFix.add("jpg");
+ picPostFix.add("pcx");
+ picPostFix.add("emf");
+ picPostFix.add("gif");
+ picPostFix.add("bmp");
+ picPostFix.add("tga");
+ picPostFix.add("jpeg");
+ picPostFix.add("tif");
+ picPostFix.add("png");
+ picPostFix.add("rle");
+ localFileFix = new ArrayList<>();
+ localFileFix.add("IMG_1470.JPG");
+ localFileFix.add("baidu_verify_Ep8xaWQJAI.html");
+ localFileFix.add("baidu_verify_L6sR9GjEtg.html");
+ localFileFix.add("shenma-site-verification.txt");
+ localFileFix.add("favicon.ico");
+ localFileFix.add("headerbg.jpg");
+ localFileFix.add("mang.png");
+ localFileFix.add("HotBook.apk");
+ localFileFix.add("wap_collect.js");
+ localFileFix.add("note_1.html");
+ localFileFix.add("note_2.html");
+ localFileFix.add("note_3.html");
+ localFileFix.add("note_4.html");
+ staticFileFix = new ArrayList<>();
+ staticFileFix.add("jpg");
+ staticFileFix.add("gif");
+ staticFileFix.add("bmp");
+ staticFileFix.add("jpeg");
+ staticFileFix.add("png");
+ staticFileFix.add("js");
+ staticFileFix.add("css");
+ noteURI = new ArrayList<>();
+ noteURI.add("/html/note_1.html");
+ noteURI.add("/html/note_2.html");
+
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ String forObject = null;
+ HttpServletRequest req = (HttpServletRequest) servletRequest;
+ HttpServletResponse resp = (HttpServletResponse) servletResponse;
+ String requestURL = req.getRequestURL().toString();
+ String requestURI = req.getRequestURI();
+ if(requestURL.contains("www.zinglizingli.xyz") || requestURL.contains("sf.zinglizingli.xyz")){
+ if(requestURI.matches("/*|(/index\\.html)")){
+ String requestDispatcher = "/book/index.html";
+ if(requestURL.contains("sf.zinglizingli.xyz")){
+ requestDispatcher = "/book/searchSoftBook.html";
+ }
+ req.getRequestDispatcher(requestDispatcher).forward(servletRequest,servletResponse);
+ return;
+ }
+ filterChain.doFilter(servletRequest,servletResponse);
+ return;
+
+ }
+
+
+ try {
+ if (requestURL.contains("http://book.zinglizingli.xyz")) {
+ if(requestURI.matches("/*|(/index\\.html)")){
+ req.getRequestDispatcher("/book/index.html").forward(servletRequest,servletResponse);
+ return;
+ }
+
+ filterChain.doFilter(servletRequest, servletResponse);
+ return;
+ }
+
+ if (requestURL.matches("http://m.zinglizingli.xyz(/*|(/index\\.html))") || requestURI.startsWith("/static/")) {
+ filterChain.doFilter(req, resp);
+ return;
+ }
+
+
+ if (cacheUtil == null) {
+ cacheUtil = SpringUtil.getBean(CommonCacheUtil.class);
+ }
+
+ if (requestURL.contains("http://m.zinglizingli.xyz/search")) {
+ //搜索跳转
+ Map otherParam = new HashMap<>();
+ otherParam.put("t", "1");
+ otherParam.put("keyword", req.getParameter("q"));
+ String realURL = "https://m.biquta.com/SearchBook.php";
+ forObject = postBiquta(req, realURL, otherParam);
+ resp.setCharacterEncoding("utf-8");
+
+ } else {
+
+ final String method = req.getMethod();
+ if (requestURL.contains("www.zinglizingli.xyz")) {
+
+ String realUrl = "https://m.biquge.info" + requestURI;
+
+ String postFix = requestURI.substring(requestURI.lastIndexOf(".") + 1);
+
+
+ // 案例:充当客户端通过restTemplate请求网络数据,并充当服务端将数据返回给浏览器
+ // 客户端请求数据:输入流(byte[])==》字符串
+ // 服务端响应数据:字符串 == 》 输出流(byte[])
+
+ //默认方式:
+ //RestTemplate restTemplate = new RestTemplate();
+ // ①当返回的response-header的content-type属性有charset值时,
+ // restTemplate的StringHttpMessageConverter会设置默认charset为content-type属性
+ // charset值
+ // StringHttpMessageConverter.setDefaultCharset(Charset.forName(charset));
+ // ②当返回的response-header的content-type属性没有charset值时
+ // restTemplate的StringHttpMessageConverter会使用默认的charset即ISO-8859-1
+
+ if (picPostFix.contains(postFix)) {
+ // 对服务端请求返回的输入流(byte[])采用何种编码转换成字符串(String)
+ restTemplate = RestTemplateUtil.getInstance("ISO-8859-1");//请求图片
+ realUrl = "https://www.biquge.info" + requestURI;
+ resp.setContentType("image/apng");
+ } else {
+ // 对服务端请求返回的输入流(byte[])采用何种编码转换成字符串(String)
+ restTemplate = RestTemplateUtil.getInstance("utf-8");//请求html/css/js等文件
+ // 对客户端响应返回的字符串(String)采用何种编码转换成输出流(byte[])
+ resp.setCharacterEncoding("utf-8");
+ setContentType(postFix, resp);
+
+ /*//=====现在浏览器有编码自动识别功能,所以上面的代码没有加content-type的Header也没有问题==========
+ //=====正确做法应该是下面代码片段1和代码片段2二选一==========
+
+ //===============================================代码片段1===============================
+ // 对客户端响应返回的字符串(String)采用何种编码转换成输出流(byte[])
+ resp.setCharacterEncoding("utf-8");
+ // 告诉浏览器对服务端请求返回的输入流(byte[])采用何种编码转换成字符串(String)显示
+ resp.setHeader("content-type", "text/html;charset=utf-8");
+ //===============================================代码片段1===============================
+
+
+ //===============================================代码片段2===============================
+ //对客户端响应返回的字符串(String)采用何种编码转换成输出流(byte[])
+ //并且告诉浏览器对服务端请求返回的输入流(byte[])采用何种编码转换成字符串(String)显示
+ resp.setContentType("text/html;charset=utf-8");
+ //===============================================代码片段2===============================
+*/
+ }
+
+
+ if (HttpMethod.GET.name().equals(method)) {
+
+
+ String fileName = requestURI.substring(requestURI.lastIndexOf("/") + 1);
+ if (localFileFix.contains(fileName) || fileName.startsWith("9a4a540e-1759-4268-90fa-7fb652c3604a.")) {
+ filterChain.doFilter(servletRequest, servletResponse);
+ return;
+ }
+
+
+ if (requestURI.matches(SUANWEI_BOOK_HTML_REGEX)) {
+ realUrl = realUrl.substring(0, realUrl.length() - 5);
+ }
+
+ String queryString = req.getQueryString();
+ if (queryString != null && queryString.length() > 0 && !queryString.contains("bsh_bid=")) {
+ queryString = "?" + URLDecoder.decode(req.getQueryString());
+ } else {
+ queryString = "";
+ }
+ realUrl = realUrl + queryString;
+
+
+ forObject = cacheUtil.get(realUrl);
+ if (forObject == null) {
+
+
+ ResponseEntity forEntity = restTemplate.getForEntity(realUrl, String.class);
+ forObject = forEntity.getBody();
+
+ // forObject = new String(forObject.getBytes("ISO-8859-1"),"utf-8");
+ if (!picPostFix.contains(postFix)) {
+ forObject = forObject.replaceAll("https://m.biquge.info", "http://www.zinglizingli.xyz")
+ .replaceAll("https://www.biquge.info", "http://www.zinglizingli.xyz")
+ .replaceAll("笔趣岛", "酸味书屋")
+ .replaceAll("笔趣阁", "酸味书屋")
+ .replaceAll("登录 ", "登录 ")
+ .replaceAll("", "")
+ .replaceFirst("", "")
+ .replaceAll(" ", "")
+ .replaceAll("https://zhannei.baidu.com/cse", "http://m.zinglizingli.xyz")
+ .replaceAll("返回 ", "返回 ")
+ .replaceAll("加入书架 ", "加入收藏 ")
+ .replaceFirst("", "\n")//页面访问自动推送到百度
+ .replaceAll("", "")//去除广告
+ ;
+ forObject = addAttacDivForSearch(forObject, requestURI);
+
+ forObject = setBookURIToHTML(forObject, SUANWEI_BOOK_REGEX);
+
+ if (requestURI.matches(SUANWEI_BOOK_HTML_REGEX)) {
+ Pattern pattern = Pattern.compile("(.+)\\s+目录共\\d+章 ");
+ Matcher matcher = pattern.matcher(forObject);
+ String title = "";
+ if (matcher.find()) {
+ title = matcher.group(1);
+ }// 类别:武侠仙侠
+ pattern = Pattern.compile("作者:(.+)
");
+ matcher = pattern.matcher(forObject);
+ String author = "";
+ if (matcher.find()) {
+ author = matcher.group(1);
+ }
+ pattern = Pattern.compile("(.+) ");
+ matcher = pattern.matcher(forObject);
+ String sort = "";
+ if (matcher.find()) {
+ sort = matcher.group(1);
+ }
+ String desc = title + "," + title + "小说最新章节免费在线阅读、最新章节列表," + title + "小说最新更新免费提供,《" + title + "》是一本情节与文笔俱佳的" + sort + "小说,由作者" + author + "创建。";
+
+ forObject = forObject.replaceFirst(" ]+\"\\s*/?>", "");//[^>]+表示1个或多个不是>的字符
+ forObject = forObject.replaceFirst("", " ");
+
+
+ }
+
+ if ("/".equals(requestURI)) {
+ forObject = forObject.replaceFirst(" ]+\"\\s*/?>", "");//[^>]+表示1个或多个不是>的字符
+ forObject = forObject.replaceFirst("", " ");
+
+
+ }
+ }
+ long timeout = 1800;
+ if (staticFileFix.contains(postFix)) {
+ timeout = 60 * 60 * 24;
+ }
+ cacheUtil.set(realUrl, forObject, timeout);
+ }
+
+
+
+ } else {
+
+
+ Map oldParameterMap = req.getParameterMap();
+ Map newParameterMap = new HashMap<>();
+ Set> entries = oldParameterMap.entrySet();
+ for (Map.Entry entry : entries) {
+ newParameterMap.put(entry.getKey(), entry.getValue()[0]);
+ }
+
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ map.setAll(newParameterMap);
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ HttpEntity> request = new HttpEntity<>(map, headers);
+ forObject = restTemplate.postForEntity(realUrl, request, String.class).getBody();
+ // forObject = new String(forObject.getBytes("ISO-8859-1"),"utf-8");
+ forObject = forObject.replaceAll("https://m.biquge.info", "http://www.zinglizingli.xyz")
+ .replaceAll("https://www.biquge.info", "http://www.zinglizingli.xyz")
+ .replaceAll("笔趣岛", "酸味书屋")
+ .replaceAll("笔趣阁", "酸味书屋")
+ .replaceAll("https://zhannei.baidu.com/cse", "http://m.zinglizingli.xyz")
+ .replaceFirst("", "")
+ .replaceAll("书架 ", "笔记 ")
+ .replaceAll("返回 ", "返回 ")
+ ;
+ forObject = setBookURIToHTML(forObject, SUANWEI_BOOK_REGEX);
+ //resp.setCharacterEncoding("utf-8");
+ //setContentType(postFix, resp);
+
+ }
+
+
+ } else if (requestURL.contains("m.zinglizingli.xyz")) {
+ String realUrl = "https://m.biquta.com" + requestURI;
+
+ String postFix = requestURI.substring(requestURI.lastIndexOf(".") + 1);
+ if (picPostFix.contains(postFix)) {
+ restTemplate = RestTemplateUtil.getInstance("ISO-8859-1");//请求图片
+ resp.setContentType("image/apng");
+ } else {
+ restTemplate = RestTemplateUtil.getInstance("utf-8");//请求html/css/js等文件
+ resp.setCharacterEncoding("utf-8");
+ setContentType(postFix, resp);
+
+ }
+
+
+ if (HttpMethod.GET.name().equals(method)) {
+
+ String fileName = requestURI.substring(requestURI.lastIndexOf("/") + 1);
+
+ if (localFileFix.contains(fileName) || fileName.startsWith("9a4a540e-1759-4268-90fa-7fb652c3604a.")) {
+ filterChain.doFilter(servletRequest, servletResponse);
+ return;
+ }
+
+
+ if (requestURI.matches(XIYANGYANG_BOOK_HTML_REGEX)) {
+ realUrl = realUrl.substring(0, realUrl.length() - 5);
+ }
+ String queryString = req.getQueryString();
+ if (queryString != null && queryString.length() > 0 && !queryString.contains("bsh_bid=")) {
+ queryString = "?" + URLDecoder.decode(req.getQueryString());
+ } else {
+ queryString = "";
+ }
+ realUrl = realUrl + queryString;
+
+
+ forObject = cacheUtil.get(realUrl);
+ if (forObject == null) {
+ forObject = restTemplate.getForEntity(realUrl, String.class).getBody();
+
+ if (!picPostFix.contains(postFix)) {
+ forObject = forObject.replaceAll("https://m.biquta.com", "http://m.zinglizingli.xyz")
+ .replaceAll("笔趣阁", "看小说吧")
+ .replaceAll("笔趣塔", "看小说吧")
+ .replaceFirst("看小说吧手机版-看小说吧 ", "看小说吧 ")
+ .replaceFirst("content=\"看小说吧\"", "content=\"小说阅读,小说排行,好看小说排行,热门小说排行,小说阅读手机版\"")
+ .replaceAll("登录 ", "登录 ")
+ .replaceFirst("", " ")
+ .replaceAll("书架 ", "收藏 ")
+ .replaceAll("加入书架 ", "加入收藏 ")
+ .replaceAll("我的书架 ", "")
+ .replaceFirst("阅读记录 ","客户端下载 ")
+ .replaceAll("我的书架 ", "轻小说 精品小说 ")
+ .replaceAll("", "")
+
+ .replaceFirst("", "\n")
+
+ .replaceFirst("", "\n")//页面访问自动推送到百度
+ .replaceAll("", "");//去除广告
+
+ forObject = addAttacDivForSearch(forObject, requestURI);
+
+ forObject = setBookURIToHTML(forObject, XIYANGYANG_BOOK_REGEX);
+
+ if (requestURI.matches(XIYANGYANG_BOOK_HTML_REGEX)) {
+ Pattern pattern = Pattern.compile("(.+) ");
+ Matcher matcher = pattern.matcher(forObject);
+ String title = "";
+ if (matcher.find()) {
+ title = matcher.group(1);
+ }// 类别:武侠仙侠
+ pattern = Pattern.compile("作者:(.+) ");
+ matcher = pattern.matcher(forObject);
+ String author = "";
+ if (matcher.find()) {
+ author = matcher.group(1);
+ }
+ pattern = Pattern.compile("\\s+类别:(.+) ");
+ matcher = pattern.matcher(forObject);
+ String sort = "";
+ if (matcher.find()) {
+ sort = matcher.group(1);
+ }
+ String desc = title + "," + title + "小说最新章节免费在线阅读、最新章节列表," + title + "小说最新更新免费提供,《" + title + "》是一本情节与文笔俱佳的" + sort + "小说,由作者" + author + "创建。";
+
+ forObject = forObject.replaceFirst(" ]+\"\\s*/?>", "");//[^>]+表示1个或多个不是>的字符
+ forObject = forObject.replaceFirst("", " ");
+
+
+ }
+
+ if ("/".equals(requestURI)) {
+ forObject = forObject.replaceFirst(" ]+\"\\s*/?>", "");//[^>]+表示1个或多个不是>的字符
+ forObject = forObject.replaceFirst("", " ");
+
+ /*forObject = forObject.replaceFirst("", "" + jsString)
+ .replaceFirst("", "" + imagDiv);*/
+ // forObject = forObject.replaceFirst("", "" + imagDiv);
+
+
+ }
+ }
+
+ // forObject = forObject.replaceFirst("", "分享按钮 \n" +
+ // " ");
+
+ /* if (forObject.contains("class=\"sortChannel_nav\"") || forObject.contains("channelHeader2")) {
+ forObject = forObject.replaceFirst("class=\"searchForm\"", "class=\"searchForm\" style=\"display:none\"");
+
+ }*/
+ long timeout = 1800;
+ if (staticFileFix.contains(postFix)) {
+ timeout = 60 * 60 * 24;
+ }
+ cacheUtil.set(realUrl, forObject, timeout);
+ }
+
+
+ } else {
+ forObject = postBiquta(req, realUrl, null);
+ }
+ } else {
+ return;
+ }
+ }
+
+ } catch (RuntimeException e) {
+ log.error(e.getMessage(), e);
+ if (e instanceof HttpClientErrorException && (((HttpClientErrorException) e).getStatusCode() == HttpStatus.NOT_FOUND)) {
+ //404
+ resp.sendRedirect("/");
+ return;
+ } else {
+ req.getRequestDispatcher("/mang.html").forward(servletRequest, servletResponse);
+ return;
+ }
+
+
+ //resp.setCharacterEncoding("utf-8");
+
+ }
+ resp.getWriter().print(forObject);
+ return;
+ }
+
+ private String addAttacDivForSearch(String forObject, String requestURI) {
+ try {
+ if (requestURI.endsWith(".html") || requestURI.equals("/")) {
+ String hotNewsDiv = cacheUtil.get("hotNewsDiv");
+ if (hotNewsDiv == null) {
+ MultiValueMap mmap = new LinkedMultiValueMap<>();
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Host", "channel.chinanews.com");
+ headers.add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
+ HttpEntity> request = new HttpEntity<>(mmap, headers);
+ String body = restTemplate.postForEntity("http://channel.chinanews.com/cns/cjs/sh.shtml", request, String.class).getBody();
+ Pattern pattern = Pattern.compile("specialcnsdata\\s*=\\s*\\{\"docs\":(.+)};\\s+newslist\\s*=\\s*specialcnsdata;");
+ Matcher matcher = pattern.matcher(body);
+ if (matcher.find()) {
+ String jsonResult = matcher.group(1);
+ if (jsonResult.length() > 5) {
+ List> list = new ObjectMapper().readValue(jsonResult, List.class);
+ StringBuilder hotContent = new StringBuilder();
+ for (Map map : list) {
+ hotContent.append("\n");
+ hotContent.append("\n");
+ hotContent.append(map.get("pubtime"));
+ hotContent.append(" \n");
+ hotContent.append("\n");
+ hotContent.append(map.get("title"));
+ hotContent.append(" \n");
+ hotContent.append("\n");
+ hotContent.append(map.get("content"));
+ hotContent.append(" \n");
+ hotContent.append("\n");
+ hotContent.append(" ");
+ hotContent.append(" \n");
+ hotContent.append(" \n");
+ }
+ hotNewsDiv = "" + hotContent.toString() + "
";
+ cacheUtil.set("hotNewsDiv", hotNewsDiv, 60 * 60 * 24);
+ forObject = forObject.replaceFirst("", hotNewsDiv + "");
+ }
+ }
+ } else {
+ forObject = forObject.replaceFirst("", hotNewsDiv + "");
+
+ }
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ } finally {
+
+ }
+
+ return forObject;
+ }
+
+ private String setBookURIToHTML(String forObject, String regex) {
+ String result = forObject;
+
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(forObject);
+ boolean isFind = matcher.find();
+ if (isFind) {
+
+ while (isFind) {
+ String booURI = matcher.group(1);
+ String htmlBooURI = booURI.substring(0, booURI.length()) + ".html";
+ result = result.replaceFirst(booURI + "/", htmlBooURI);
+ isFind = matcher.find();
+ }
+
+
+ }
+
+ return result;
+ }
+
+ private String postBiquta(HttpServletRequest req, String realUrl, Map otherParam) {
+ String forObject;
+ Map oldParameterMap = req.getParameterMap();
+ Map newParameterMap = new HashMap<>();
+ Set> entries = oldParameterMap.entrySet();
+ for (Map.Entry entry : entries) {
+ newParameterMap.put(entry.getKey(), entry.getValue()[0]);
+ }
+ if (otherParam != null) {
+ newParameterMap.putAll(otherParam);
+ }
+
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ map.setAll(newParameterMap);
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ HttpEntity> request = new HttpEntity<>(map, headers);
+ forObject = restTemplate.postForEntity(realUrl, request, String.class).getBody();
+ forObject = forObject.replaceAll("https://m.biquta.com", "http://m.zinglizingli.xyz")
+ .replaceAll("笔趣阁", "看小说吧")
+ .replaceAll("笔趣塔", "看小说吧")
+ .replaceFirst("看小说吧手机版-看小说吧 ", "看小说吧 ")
+ .replaceFirst("content=\"看小说吧\"", "content=\"小说阅读,小说排行,好看小说排行,热门小说排行,小说阅读手机版\"")
+ .replaceFirst("", " ")
+ .replaceAll("我的书架 ", "轻小说 精品小说 ")
+ .replaceFirst("阅读记录 ","客户端下载 ")
+ .replaceFirst("", "\n")
+ ;
+
+ forObject = setBookURIToHTML(forObject, XIYANGYANG_BOOK_REGEX);
+ return forObject;
+ }
+
+ private void setContentType(String fileFix, HttpServletResponse resp) {
+ String contentType = "text/html";
+ switch (fileFix) {
+ case "js": {
+ contentType = "application/javascript";
+ break;
+ }
+ case "css": {
+ contentType = "text/css";
+ break;
+ }
+ case "html": {
+ contentType = "text/html";
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ resp.setContentType(contentType);
+
+
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/schedule/CrawlBooksSchedule.java b/src/main/java/xyz/zinglizingli/search/schedule/CrawlBooksSchedule.java
new file mode 100644
index 0000000..f798f80
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/schedule/CrawlBooksSchedule.java
@@ -0,0 +1,865 @@
+package xyz.zinglizingli.search.schedule;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.po.BookContent;
+import xyz.zinglizingli.books.po.BookIndex;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.books.util.ExcutorUtils;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Service
+public class CrawlBooksSchedule {
+
+
+ private Logger log = LoggerFactory.getLogger(CrawlBooksSchedule.class);
+
+
+ @Autowired
+ private BookService bookService;
+
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+
+
+ private boolean isExcuting = false;
+
+
+ public static void main(String[] args) {//
+ String forObject = " ";
+
+ Pattern pattern = Pattern.compile("
+//
+//
+//
+//
+//
+ //第一周期全部书拉取完后,可进行第二周期,只拉取前面几页的数据,拉取时间间隔变小
+ for (int i = 1; i <= 7; i++) {
+
+ int finalI = i;
+ new Thread(
+ () -> {
+
+ try {
+ //拼接分类URL
+ int page = 1;//起始页码
+ int totalPage = page;
+ String catBookListUrl = baseUrl + "/class/" + finalI + "/" + page + ".html";
+ ResponseEntity forEntity = restTemplate.getForEntity(catBookListUrl, String.class);
+ if (forEntity.getStatusCode() == HttpStatus.OK) {
+ String forObject = forEntity.getBody();
+ //匹配分页数
+ Pattern pattern = Pattern.compile("value=\"(\\d+)/(\\d+)\"");
+ Matcher matcher = pattern.matcher(forObject);
+ boolean isFind = matcher.find();
+ System.out.println("匹配分页数" + isFind);
+ if (isFind) {
+ int currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ //解析第一页书籍的数据
+ Pattern bookPatten = Pattern.compile("href=\"/(\\d+_\\d+)/\"");
+ parseBook(bookPatten, forObject, restTemplate, finalI, baseUrl);
+ /*while (currentPage < totalPage) {
+ catBookListUrl = baseUrl + "/class/" + finalI + "/" + (currentPage + 1) + ".html";
+ forEntity = restTemplate.getForEntity(catBookListUrl, String.class);
+ if (forEntity.getStatusCode() == HttpStatus.OK) {
+ forObject = forEntity.getBody();
+ //匹配分页数
+ matcher = pattern.matcher(forObject);
+ isFind = matcher.find();
+
+ if (isFind) {
+ currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ parseBook(bookPatten, forObject, restTemplate, finalI, baseUrl);
+ }
+ }else{
+ currentPage++;
+ }
+ }*/
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ ).start();
+
+
+ }
+
+
+ System.out.println("结束时间" + new Date());
+
+ }
+
+
+ // @Scheduled(fixedRate = 1000 * 60 * 30)
+ //@Scheduled(fixedRate = 1000 * 60 * 60 * 3)//本机更新,否则服务器压力过大,等书籍多了之后,再去服务器更新,这样更新数量不会很大
+ //暂定2小说,只爬分类前3本书,一共3*7=21本书,爬等以后书籍多了之后,会适当缩短更新间隔
+ public void crawBqugeTaBooks() throws Exception {
+ if (!isExcuting) {
+ isExcuting = true;
+ final String baseUrl = "https://m.biquta.com";
+ log.debug("crawlBooksSchedule执行中。。。。。。。。。。。。");
+
+
+//①爬分类列表的书籍url和总页数
+// https:
+////m.biquta.com/class/1/1.html
+// https:
+////m.biquta.com/class/2/1.html
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+//
+//
+//
+//
+ //第一周期全部书拉取完后,可进行第二周期,只拉取前面几页的数据,拉取时间间隔变小
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+ while (true) {
+ log.debug("crawlBooksSchedule循环执行中。。。。。。。。。。。。");
+ Set classIdSet = new HashSet<>();
+ for (int i = 1; i <= 7; i++) {
+
+ log.debug("crawlBooksSchedule分类" + i + "执行中。。。。。。。。。。。。");
+
+ // int finalI = i;
+ /* new Thread(
+ () -> {*/
+
+ try {
+ //先随机更新分类
+ Random random = new Random();
+ int finalI = random.nextInt(7) + 1;
+ if (classIdSet.contains(finalI)) {
+ finalI = random.nextInt(7) + 1;
+ }
+ classIdSet.add(finalI);
+ //拼接分类URL
+ int page = 1;//起始页码
+ int totalPage = page;
+ String catBookListUrl = baseUrl + "/class/" + finalI + "/" + page + ".html";
+ String forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ Pattern pattern = Pattern.compile("value=\"(\\d+)/(\\d+)\"");
+ Matcher matcher = pattern.matcher(forObject);
+ boolean isFind = matcher.find();
+ System.out.println("匹配分页数" + isFind);
+ if (isFind) {
+ int currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ //解析第一页书籍的数据
+ Pattern bookPatten = Pattern.compile("href=\"/(\\d+_\\d+)/\"");
+ parseBook(bookPatten, forObject, restTemplate, finalI, baseUrl);
+ /* while (currentPage < totalPage) {
+ catBookListUrl = baseUrl + "/bqgeclass/" + finalI + "/" + (currentPage + 1) + ".html";
+ forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ matcher = pattern.matcher(forObject);
+ isFind = matcher.find();
+
+ if (isFind) {
+ currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ parseBiquge11Book(bookPatten, forObject, finalI, baseUrl);
+ }
+ } else {
+ currentPage++;
+ }
+ }*/
+ }
+ }
+ Thread.sleep(1000 * 60 * 10);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ /* }
+ ).start();*/
+
+
+ }
+ }
+
+ }
+
+
+ }
+
+
+ //@Scheduled(fixedRate = 1000 * 60 * 35)
+ @Scheduled(fixedRate = 1000 * 60 * 60 * 3)
+ //暂定2小说,只爬分类前3本书,一共3*7=21本书,爬等以后书籍多了之后,会适当缩短更新间隔
+ public void crawBquge11BooksAtDay() throws Exception {
+ if (!isExcuting) {
+ isExcuting = true;
+ final String baseUrl = "https://m.biqudao.com";
+ log.debug("crawlBooksSchedule执行中。。。。。。。。。。。。");
+
+
+//①爬分类列表的书籍url和总页数
+// https:
+////m.biquta.com/class/1/1.html
+// https:
+////m.biquta.com/class/2/1.html
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+//
+//
+//
+//
+ //第一周期全部书拉取完后,可进行第二周期,只拉取前面几页的数据,拉取时间间隔变小
+ while (true) {
+ log.debug("crawlBooksSchedule循环执行中。。。。。。。。。。。。");
+ //List classIdList = new ArrayList<>(Arrays.asList(new Integer[]{1,2,3,4,5,6,7}));
+ // for (int i = 1; i <= 7; i++) {
+
+ // log.debug("crawlBooksSchedule分类"+i+"执行中。。。。。。。。。。。。");
+
+ // int finalI = i;
+ /* new Thread(
+ () -> {*/
+
+ try {
+ //先随机更新分类
+ //Random random = new Random();
+ //int finalI = classIdList.get(new Random().nextInt(classIdList.size()));
+ //classIdList.remove(finalI);
+ int finalI = 0;
+ //拼接分类URL
+ int page = 1;//起始页码
+ int totalPage = page;
+ String catBookListUrl = baseUrl + "/bqgeclass/" + finalI + "/" + page + ".html";
+ String forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ Pattern pattern = Pattern.compile("value=\"(\\d+)/(\\d+)\"");
+ Matcher matcher = pattern.matcher(forObject);
+ boolean isFind = matcher.find();
+ System.out.println("匹配分页数" + isFind);
+ if (isFind) {
+ int currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ //解析第一页书籍的数据
+ Pattern bookPatten = Pattern.compile("href=\"/(bqge\\d+)/\"");
+ //白天更新
+ parseBiquge11Book(bookPatten, forObject, finalI, baseUrl, true);
+ /* while (currentPage < totalPage) {
+ catBookListUrl = baseUrl + "/bqgeclass/" + finalI + "/" + (currentPage + 1) + ".html";
+ forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ matcher = pattern.matcher(forObject);
+ isFind = matcher.find();
+
+ if (isFind) {
+ currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ parseBiquge11Book(bookPatten, forObject, finalI, baseUrl);
+ }
+ } else {
+ currentPage++;
+ }
+ }*/
+ }
+ }
+ Thread.sleep(1000 * 60 * 5);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ /* }
+ ).start();*/
+
+
+ // }
+ }
+
+ }
+
+
+ }
+
+
+ @Scheduled(cron = "0 0 2 * * ?")
+ //暂定2小说,只爬分类前3本书,一共3*7=21本书,爬等以后书籍多了之后,会适当缩短更新间隔
+ public void crawBquge11BooksAtNight() throws Exception {
+ final String baseUrl = "https://m.biqudao.com";
+ log.debug("crawlBooksSchedule执行中。。。。。。。。。。。。");
+
+
+//①爬分类列表的书籍url和总页数
+// https:
+////m.biquta.com/class/1/1.html
+// https:
+////m.biquta.com/class/2/1.html
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+// https:
+////m.biquta.com/class/2/2.html
+//
+//
+//
+//
+//
+//
+ //第一周期全部书拉取完后,可进行第二周期,只拉取前面几页的数据,拉取时间间隔变小
+ log.debug("crawlBooksSchedule循环执行中。。。。。。。。。。。。");
+ //List classIdList = new ArrayList<>(Arrays.asList(new Integer[]{1,2,3,4,5,6,7}));
+ // for (int i = 1; i <= 7; i++) {
+
+ // log.debug("crawlBooksSchedule分类"+i+"执行中。。。。。。。。。。。。");
+
+ // int finalI = i;
+ /* new Thread(
+ () -> {*/
+
+ try {
+ //先随机更新分类
+ //Random random = new Random();
+ //int finalI = classIdList.get(new Random().nextInt(classIdList.size()));
+ //classIdList.remove(finalI);
+ int finalI = 0;
+ //拼接分类URL
+ int page = 1;//起始页码
+ int totalPage = page;
+ String catBookListUrl = baseUrl + "/bqgeclass/" + finalI + "/" + page + ".html";
+ String forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ Pattern pattern = Pattern.compile("value=\"(\\d+)/(\\d+)\"");
+ Matcher matcher = pattern.matcher(forObject);
+ boolean isFind = matcher.find();
+ System.out.println("匹配分页数" + isFind);
+ if (isFind) {
+ int currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ //解析第一页书籍的数据
+ Pattern bookPatten = Pattern.compile("href=\"/(bqge\\d+)/\"");
+ //晚上插入
+ parseBiquge11Book(bookPatten, forObject, finalI, baseUrl, false);
+ while (currentPage < totalPage) {
+ if (new Date().getHours() > 5) {
+ break;
+ }
+ catBookListUrl = baseUrl + "/bqgeclass/" + finalI + "/" + (currentPage + 1) + ".html";
+ forObject = getByHttpClient(catBookListUrl);
+ if (forObject != null) {
+ //匹配分页数
+ matcher = pattern.matcher(forObject);
+ isFind = matcher.find();
+
+ if (isFind) {
+ currentPage = Integer.parseInt(matcher.group(1));
+ totalPage = Integer.parseInt(matcher.group(2));
+ parseBiquge11Book(bookPatten, forObject, finalI, baseUrl, false);
+ }
+ } else {
+ currentPage++;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ /* }
+ ).start();*/
+
+
+ // }
+
+
+ }
+
+ private void parseBiquge11Book(Pattern bookPatten, String forObject, int catNum, String baseUrl, boolean isUpdate) {
+
+ Matcher matcher2 = bookPatten.matcher(forObject);
+ boolean isFind = matcher2.find();
+ Pattern scorePatten = Pattern.compile("(\\d+\\.\\d+)分
");
+ Matcher scoreMatch = scorePatten.matcher(forObject);
+ boolean scoreFind = scoreMatch.find();
+
+ Pattern bookNamePatten = Pattern.compile("([^/]+)
");
+ Matcher bookNameMatch = bookNamePatten.matcher(forObject);
+ boolean isBookNameMatch = bookNameMatch.find();
+
+
+ System.out.println("匹配书籍url" + isFind);
+
+ System.out.println("匹配分数" + scoreFind);
+
+ while (isFind && scoreFind && isBookNameMatch) {
+
+ try {
+ Float score = Float.parseFloat(scoreMatch.group(1));
+
+ if (score < 8.0) {//数据库空间有效暂时爬取7.5分以上的小说
+ continue;
+ }
+
+ String bokNum = matcher2.group(1);
+ String bookUrl = baseUrl + "/" + bokNum + "/";
+
+ String body = getByHttpClient(bookUrl);
+ if (body != null) {
+
+ String bookName = bookNameMatch.group(1);
+ Pattern authorPatten = Pattern.compile("作者:([^/]+) ");
+ Matcher authoreMatch = authorPatten.matcher(body);
+ if (authoreMatch.find()) {
+ String author = authoreMatch.group(1);
+
+ Pattern statusPatten = Pattern.compile("状态:([^/]+)");
+ Matcher statusMatch = statusPatten.matcher(body);
+ if (statusMatch.find()) {
+ String status = statusMatch.group(1);
+
+ Pattern catPatten = Pattern.compile("类别:([^/]+)");
+ Matcher catMatch = catPatten.matcher(body);
+ if (catMatch.find()) {
+ String catName = catMatch.group(1);
+ switch (catName) {
+ case "玄幻奇幻": {
+ catNum = 1;
+ break;
+ }
+ case "武侠仙侠": {
+ catNum = 2;
+ break;
+ }
+ case "都市言情": {
+ catNum = 3;
+ break;
+ }
+ case "历史军事": {
+ catNum = 4;
+ break;
+ }
+ case "科幻灵异": {
+ catNum = 5;
+ break;
+ }
+ case "网游竞技": {
+ catNum = 6;
+ break;
+ }
+ case "女生频道": {
+ catNum = 7;
+ break;
+ }
+ default: {
+ catNum = 1;
+ break;
+ }
+ }
+ Pattern updateTimePatten = Pattern.compile("更新:(\\d+-\\d+-\\d+\\s\\d+:\\d+:\\d+) ");
+ Matcher updateTimeMatch = updateTimePatten.matcher(body);
+ if (updateTimeMatch.find()) {
+ String updateTimeStr = updateTimeMatch.group(1);
+ SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
+ Date updateTime = format.parse(updateTimeStr);
+ Pattern picPatten = Pattern.compile(" ]+)\"\\s+onerror=\"this.src=");
+ Matcher picMather = picPatten.matcher(body);
+ if (picMather.find()) {
+ String picSrc = picMather.group(1);
+
+ Pattern descPatten = Pattern.compile("class=\"review\">([^<]+)
");
+ Matcher descMatch = descPatten.matcher(body);
+ if (descMatch.find()) {
+ String desc = descMatch.group(1);
+
+
+ Book book = new Book();
+ book.setAuthor(author);
+ book.setCatid(catNum);
+ book.setBookDesc(desc);
+ book.setBookName(bookName);
+ book.setScore(score);
+ book.setPicUrl(picSrc);
+ book.setBookStatus(status);
+ book.setUpdateTime(updateTime);
+
+ List indexList = new ArrayList<>();
+ List contentList = new ArrayList<>();
+
+ //读取目录
+ Pattern indexPatten = Pattern.compile("查看完整目录 ");
+ Matcher indexMatch = indexPatten.matcher(body);
+ if (indexMatch.find()) {
+ String indexUrl = baseUrl + indexMatch.group(1);
+ String body2 = getByHttpClient(indexUrl);
+ if (body2 != null) {
+ Pattern indexListPatten = Pattern.compile("([^/]+) ");
+ Matcher indexListMatch = indexListPatten.matcher(body2);
+
+ boolean isFindIndex = indexListMatch.find();
+
+ int indexNum = 0;
+
+ //查询该书籍已存在目录号
+ List hasIndexNum = bookService.queryIndexCountByBookNameAndBAuthor(bookName, author);
+ //更新和插入分别开,插入只在凌晨做一次
+ if ((isUpdate && hasIndexNum.size() > 0) || (!isUpdate && hasIndexNum.size() == 0)) {
+ while (isFindIndex) {
+ if (!hasIndexNum.contains(indexNum)) {
+
+ String contentUrl = baseUrl + indexListMatch.group(1);
+ String indexName = indexListMatch.group(2);
+
+
+ //查询章节内容
+ String body3 = getByHttpClient(contentUrl);
+ if (body3 != null) {
+ Pattern contentPattten = Pattern.compile("章节错误,点此举报(.*)加入书签,方便阅读");
+ String start = "『章节错误,点此举报』";
+ String end = "『加入书签,方便阅读』";
+ String content = body3.substring(body3.indexOf(start) + start.length(), body3.indexOf(end));
+ //TODO插入章节目录和章节内容
+ BookIndex bookIndex = new BookIndex();
+ bookIndex.setIndexName(indexName);
+ bookIndex.setIndexNum(indexNum);
+ indexList.add(bookIndex);
+ BookContent bookContent = new BookContent();
+ bookContent.setContent(content);
+ bookContent.setIndexNum(indexNum);
+ contentList.add(bookContent);
+
+
+ } else {
+ break;
+ }
+
+
+ }
+ indexNum++;
+ isFindIndex = indexListMatch.find();
+ }
+
+ if (indexList.size() == contentList.size() && indexList.size() > 0) {
+ ExcutorUtils.excuteFixedTask(new Runnable() {
+ @Override
+ public void run() {
+ bookService.saveBookAndIndexAndContent(book, indexList, contentList);
+ }
+ });
+
+ }
+ }
+ }
+
+
+ }
+
+
+ }
+
+
+ }
+ }
+ }
+ }
+
+
+ }
+
+ }
+
+
+ } catch (Exception e) {
+
+ e.printStackTrace();
+
+ } finally {
+ matcher2.find();
+ isFind = matcher2.find();//需要找两次,应为有两个一样的路径匹配
+ scoreFind = scoreMatch.find();
+ isBookNameMatch = bookNameMatch.find();
+ }
+
+
+ }
+
+ }
+
+ private String getByHttpClient(String catBookListUrl) {
+ try {
+ /* HttpClient httpClient = new DefaultHttpClient();
+ HttpGet getReq = new HttpGet(catBookListUrl);
+ getReq.setHeader("user-agent", "Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1");
+ HttpResponse execute = httpClient.execute(getReq);
+ if (execute.getStatusLine().getStatusCode() == HttpStatus.OK.value()) {
+ HttpEntity entity = execute.getEntity();
+ return EntityUtils.toString(entity, "utf-8");
+ } else {
+ return null;
+ }*/
+ //经测试restTemplate比httpClient效率高出很多倍,所有选择restTemplate
+ ResponseEntity forEntity = restTemplate.getForEntity(catBookListUrl, String.class);
+ if (forEntity.getStatusCode() == HttpStatus.OK) {
+ return forEntity.getBody();
+ } else {
+ return null;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /***
+ * 解析书籍详情之后的页面
+ */
+ private void parseBook(Pattern bookPatten, String forObject, RestTemplate restTemplate, int catNum, String baseUrl) throws ParseException {
+ Matcher matcher2 = bookPatten.matcher(forObject);
+ boolean isFind = matcher2.find();
+ Pattern scorePatten = Pattern.compile("(\\d+\\.\\d+)分
");
+ Matcher scoreMatch = scorePatten.matcher(forObject);
+ boolean scoreFind = scoreMatch.find();
+
+ Pattern bookNamePatten = Pattern.compile("([^/]+)
");
+ Matcher bookNameMatch = bookNamePatten.matcher(forObject);
+ boolean isBookNameMatch = bookNameMatch.find();
+
+ Pattern authorPatten = Pattern.compile(">作者:([^/]+)<");
+ Matcher authoreMatch = authorPatten.matcher(forObject);
+ boolean isFindAuthor = authoreMatch.find();
+
+
+ System.out.println("匹配书籍url" + isFind);
+
+ System.out.println("匹配分数" + scoreFind);
+ while (isFind && scoreFind && isBookNameMatch && isFindAuthor) {
+
+ try {
+ Float score = Float.parseFloat(scoreMatch.group(1));
+
+ if (score < 8.0) {//数据库空间有效暂时爬取7.5分以上的小说
+ continue;
+ }
+ String bookName = bookNameMatch.group(1);
+ String author = authoreMatch.group(1);
+
+ String bokNum = matcher2.group(1);
+ String bookUrl = baseUrl + "/" + bokNum + "/";
+
+ ResponseEntity forEntity = restTemplate.getForEntity(bookUrl, String.class);
+ if (forEntity.getStatusCode() == HttpStatus.OK) {
+
+ String body = forEntity.getBody();
+
+ Pattern statusPatten = Pattern.compile("状态:([^/]+)");
+ Matcher statusMatch = statusPatten.matcher(body);
+ if (statusMatch.find()) {
+ String status = statusMatch.group(1);
+ Pattern updateTimePatten = Pattern.compile("更新:(\\d+-\\d+-\\d+\\s\\d+:\\d+:\\d+)");
+ Matcher updateTimeMatch = updateTimePatten.matcher(body);
+ if (updateTimeMatch.find()) {
+ String updateTimeStr = updateTimeMatch.group(1);
+ SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
+ Date updateTime = format.parse(updateTimeStr);
+ Pattern picPatten = Pattern.compile(" ]+)\"\\s+onerror=\"this.src=");
+ Matcher picMather = picPatten.matcher(body);
+ if (picMather.find()) {
+ String picSrc = picMather.group(1);
+
+ Pattern descPatten = Pattern.compile("class=\"review\">([^<]+)
");
+ Matcher descMatch = descPatten.matcher(body);
+ if (descMatch.find()) {
+ String desc = descMatch.group(1);
+
+
+ Book book = new Book();
+ book.setAuthor(author);
+ book.setCatid(catNum);
+ book.setBookDesc(desc);
+ book.setBookName(bookName);
+ book.setScore(score);
+ book.setPicUrl(picSrc);
+ book.setBookStatus(status);
+ book.setUpdateTime(updateTime);
+
+ List indexList = new ArrayList<>();
+ List contentList = new ArrayList<>();
+
+ //读取目录
+ Pattern indexPatten = Pattern.compile("查看完整目录 ");
+ Matcher indexMatch = indexPatten.matcher(body);
+ if (indexMatch.find()) {
+ String indexUrl = baseUrl + indexMatch.group(1);
+ ResponseEntity forEntity1 = restTemplate.getForEntity(indexUrl, String.class);
+ if (forEntity1.getStatusCode() == HttpStatus.OK) {
+ String body2 = forEntity1.getBody();
+ Pattern indexListPatten = Pattern.compile("([^/]+) ");
+ Matcher indexListMatch = indexListPatten.matcher(body2);
+
+ boolean isFindIndex = indexListMatch.find();
+
+ int indexNum = 0;
+
+ //查询该书籍已存在目录号
+ List hasIndexNum = bookService.queryIndexCountByBookNameAndBAuthor(bookName, author);
+
+ while (isFindIndex) {
+ if (!hasIndexNum.contains(indexNum)) {
+
+ String contentUrl = baseUrl + indexListMatch.group(1);
+ String indexName = indexListMatch.group(2);
+
+
+ //查询章节内容
+ ResponseEntity forEntity2 = restTemplate.getForEntity(contentUrl, String.class);
+ if (forEntity2.getStatusCode() == HttpStatus.OK) {
+ String body3 = forEntity2.getBody();
+ Pattern contentPattten = Pattern.compile("章节错误,点此举报(.*)加入书签,方便阅读");
+ String start = "『章节错误,点此举报』";
+ String end = "『加入书签,方便阅读』";
+ String content = body3.substring(body3.indexOf(start) + start.length(), body3.indexOf(end));
+ //TODO插入章节目录和章节内容
+ BookIndex bookIndex = new BookIndex();
+ bookIndex.setIndexName(indexName);
+ bookIndex.setIndexNum(indexNum);
+ indexList.add(bookIndex);
+ BookContent bookContent = new BookContent();
+ bookContent.setContent(content);
+ bookContent.setIndexNum(indexNum);
+ contentList.add(bookContent);
+
+
+ } else {
+ break;
+ }
+
+ }
+
+ indexNum++;
+ isFindIndex = indexListMatch.find();
+ }
+ if (indexList.size() == contentList.size() && indexList.size() > 0) {
+ bookService.saveBookAndIndexAndContent(book, indexList, contentList);
+ }
+
+
+ }
+ }
+
+
+ }
+
+
+ }
+ }
+
+
+ }
+
+ }
+
+ } catch (Exception e) {
+
+ e.printStackTrace();
+
+ } finally {
+ matcher2.find();
+ isFind = matcher2.find();//需要找两次,应为有两个一样的路径匹配
+ scoreFind = scoreMatch.find();
+ isBookNameMatch = bookNameMatch.find();
+ isFindAuthor = authoreMatch.find();
+ }
+
+
+ }
+
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/schedule/SendEmaillSchedule.java b/src/main/java/xyz/zinglizingli/search/schedule/SendEmaillSchedule.java
new file mode 100644
index 0000000..da0c828
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/schedule/SendEmaillSchedule.java
@@ -0,0 +1,72 @@
+package xyz.zinglizingli.search.schedule;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import xyz.zinglizingli.books.constant.CacheKeyConstans;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.books.service.MailService;
+import xyz.zinglizingli.books.util.RandomValueUtil;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+
+/*
+主动推送:最为快速的提交方式,
+建议您将站点当天新产出链接立即通过此方式推送给百度,
+以保证新链接可以及时被百度收录。
+*/
+@Service
+public class SendEmaillSchedule {
+
+ @Autowired
+ private CommonCacheUtil cacheUtil;
+
+ @Autowired
+ private MailService mailService;
+
+
+ private Logger log = LoggerFactory.getLogger(SendEmaillSchedule.class);
+
+
+ @Scheduled(cron = "0 10 17 * * *")
+ public void sendEmaill() {
+ System.out.println("SendEmaillSchedule。。。。。。。。。。。。。。。");
+
+ for(int i = 0 ; i < 1000; i++){
+ String email = RandomValueUtil.getEmail();
+ if(cacheUtil.get(CacheKeyConstans.EMAIL_URL_PREFIX_KEY+email)!=null){
+ continue;
+ }
+ cacheUtil.setObject(CacheKeyConstans.EMAIL_URL_PREFIX_KEY+email,email,60*60*24*30);
+ String subject = "推荐一个看小说的弹幕网站";
+ String content = "精品小说楼是国内优秀的小说弹幕网站 ,精品小说楼提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读 和TXT小说下载 ,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜 ,致力于无广告无弹窗 的小说阅读环境。" +
+ "点击进入 "
+ +" ";
+ mailService.sendHtmlMail(email, subject, content);
+ try {
+ Thread.sleep(new Random().nextInt(1000*60)+1000*60);
+ } catch (InterruptedException e) {
+ log.error(e.getMessage(),e);
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/schedule/SendUrlSchedule.java b/src/main/java/xyz/zinglizingli/search/schedule/SendUrlSchedule.java
new file mode 100644
index 0000000..785eec4
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/schedule/SendUrlSchedule.java
@@ -0,0 +1,83 @@
+package xyz.zinglizingli.search.schedule;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/*
+主动推送:最为快速的提交方式,
+建议您将站点当天新产出链接立即通过此方式推送给百度,
+以保证新链接可以及时被百度收录。
+*/
+@Service
+public class SendUrlSchedule {
+
+ @Autowired
+ private CommonCacheUtil cacheUtil;
+
+ @Autowired
+ private BookService bookService;
+
+ @Value("${baidu.record.ids}")
+ private String recordedIds;
+
+ private Logger log = LoggerFactory.getLogger(SendUrlSchedule.class);
+
+
+ @Scheduled(cron = "0 0 1 * * 5")
+ public void sendAllBookToBaidu() {
+ System.out.println("sendAllBookToBaidu。。。。。。。。。。。。。。。");
+
+ List recordedIdsList = Arrays.asList(recordedIds.split(","));
+ List idList = bookService.queryEndBookIdList();
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+
+
+ String reqBody = "";
+ for (String id : idList) {
+ try {
+ if (!recordedIdsList.contains(id)) {
+ reqBody += ("https://www.zinglizingli.xyz/book/" + id + ".html" + "\n");
+ //reqBody+=("http://www.zinglizingli.xyz/book/"+id+".html"+"\n");
+ if (reqBody.length() > 2000) {
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.TEXT_PLAIN);
+ //headers.add("User-Agent","curl/7.12.1");
+ headers.add("Host", "data.zz.baidu.com");
+ headers.setContentLength(reqBody.length());
+ HttpEntity request = new HttpEntity<>(reqBody, headers);
+ System.out.println("推送数据:" + reqBody);
+ ResponseEntity stringResponseEntity = restTemplate.postForEntity("http://data.zz.baidu.com/urls?site=www.zinglizingli.xyz&token=IuK7oVrPKe3U606x", request, String.class);
+ System.out.println("推送URL结果:code:" + stringResponseEntity.getStatusCode().value() + ",body:" + stringResponseEntity.getBody());
+ reqBody = "";
+ Thread.sleep(1000 * 10);
+ }
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/schedule/SendWeiboSchedule.java b/src/main/java/xyz/zinglizingli/search/schedule/SendWeiboSchedule.java
new file mode 100644
index 0000000..585070c
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/schedule/SendWeiboSchedule.java
@@ -0,0 +1,498 @@
+package xyz.zinglizingli.search.schedule;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import xyz.zinglizingli.books.po.Book;
+import xyz.zinglizingli.books.service.BookService;
+import xyz.zinglizingli.search.cache.CommonCacheUtil;
+import xyz.zinglizingli.search.utils.RestTemplateUtil;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Service
+public class SendWeiboSchedule {
+
+ @Autowired
+ private CommonCacheUtil cacheUtil;
+
+ @Autowired
+ private BookService bookService;
+
+ private Logger log = LoggerFactory.getLogger(SendWeiboSchedule.class);
+
+ private boolean isExcuting = false;//是否正在执行
+
+ private long excuteNum = 0;
+
+ @Value("${search.schedule.isRunExcute}")
+ private String isRunExcute;//是否在运行时就执行sendAtNight定时器
+
+ @Value("${browser.cookie}")
+ private String cookieStr;
+
+ private static final String BOOKNAME_CACHE_PREFIX = "bookName_Cache_Prefix:";
+
+
+ @Scheduled(fixedRate = 1000 * 60 * 35)
+ public void sendAtDay() {
+ log.debug("sendWeoboSchedule执行中。。。。。。。。。。。。");
+ if (!isExcuting) {
+ isExcuting = true;
+ excuteNum++;
+ //long sleepMillis = 1000 * 60 * 5;
+ long sleepMillis = 1000 * 60 * 5;
+ try {
+
+ String name;
+ String desc;
+ String author;
+ String bookNum;
+ String resultCode;
+ long realSleepMillis;
+
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+
+ //发送数据库中的一篇文章
+ Map dataMap = bookService.queryNewstBook();
+ log.debug("dataMap大小:" + dataMap.size());
+ if (dataMap.size() > 1) {
+ Book book = (Book) dataMap.get("book");
+ String newstIndexName = (String) dataMap.get("newstIndexName");
+ name = newstIndexName + "_" + book.getBookName();
+ desc = book.getBookDesc();
+ author = book.getAuthor();
+ bookNum = new Random().nextInt(100) + "";
+ realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ log.debug("发送微博书籍名:" + book.getBookName());
+ if (!name.equals(cacheUtil.get(BOOKNAME_CACHE_PREFIX + name))) {
+ resultCode = sendOneSiteWeibo(restTemplate, book.getBookName(), newstIndexName, author, desc, "精品小说楼", bookNum, "https://www.zinglizingli.xyz/book/" + book.getId() + ".html");
+ log.debug("发送微博书籍名:" + book.getBookName() + " 状态码:" + resultCode);
+ if ("{\"code\":\"A00006\"}".equals(resultCode)) {
+ cacheUtil.set(BOOKNAME_CACHE_PREFIX + name, name, 60 * 60 * 24 * 30);
+ }
+ Thread.sleep(realSleepMillis + 32);
+ }
+ }
+
+
+ //分享喜羊羊小说网
+ String url2 = "http://m.zinglizingli.xyz/class/0/1.html";
+
+ ResponseEntity forEntity2 = restTemplate.getForEntity(url2, String.class);
+
+
+ String forObject2 = forEntity2.getBody();
+ Pattern pattern = Pattern.compile("" +
+ "\\s* ((.*))
\\s*" +
+ "");
+ Matcher match = pattern.matcher(forObject2);
+ boolean isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+
+ float score = Float.parseFloat(match.group(4));
+
+ if (score >= 7.0) {
+
+ bookNum = match.group(1);
+ String href = "http://m.zinglizingli.xyz/" + bookNum + ".html";
+ name = match.group(2);
+ if (!name.equals(cacheUtil.get(BOOKNAME_CACHE_PREFIX + name))) {
+ author = match.group(3);
+ desc = match.group(5);
+
+ resultCode = sendOneSiteWeibo(restTemplate, name, "", author, desc, "看小说吧", bookNum, href);
+ if ("{\"code\":\"A00006\"}".equals(resultCode)) {
+ cacheUtil.set(BOOKNAME_CACHE_PREFIX + name, name, 60 * 60 * 24 * 30);
+ }
+
+ realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ Thread.sleep(realSleepMillis);
+
+ }
+ }
+ isFind = match.find();
+ }
+
+
+ }
+
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+
+ } finally {
+ isExcuting = false;
+ }
+
+ }
+
+ }
+
+ //@Scheduled(fixedRate = 1000 * 60 * 35)
+ //@Scheduled(fixedRate = 1000 * 60 * 5)
+ /*public void sendAtDay() {
+ if (!isExcuting) {
+ isExcuting = true;
+ excuteNum++;
+ //long sleepMillis = 1000 * 60 * 5;
+ long sleepMillis = 1000 * 60 * 25;
+ try {
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+ //分享酸味书屋
+ String url = "http://www.zinglizingli.xyz/paihangbang_lastupdate/1.html";
+
+ //分享喜羊羊小说网
+ String url2 = "http://m.zinglizingli.xyz/class/0/1.html";
+
+ ResponseEntity forEntity = restTemplate.getForEntity(url, String.class);
+ ResponseEntity forEntity2 = restTemplate.getForEntity(url2, String.class);
+
+ String forObject = forEntity.getBody();
+ Pattern pattern = Pattern.compile("\n" +
+ "(.*) \n" +
+ "(.*) \n" +
+ "(.*)\\.\\.\\. \n" +
+ "(\\d*) 人在看 \n" +
+ " ");
+ Matcher match = pattern.matcher(forObject);
+ boolean isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+
+ int lookNum = Integer.parseInt(match.group(5));
+ if (lookNum > 5000) {
+ String bookNum = match.group(1);
+ String href = "http://www.zinglizingli.xyz/" + bookNum + ".html";
+ String name = match.group(2);
+ log.debug(excuteNum + ":" + name + "_BOOKNAME_CACHE:" + cacheUtil.get(BOOKNAME_CACHE_PREFIX + name));
+ if (!name.equals(cacheUtil.get(BOOKNAME_CACHE_PREFIX + name))) {
+
+ String author = match.group(3);
+ String desc = match.group(4);
+ log.debug(excuteNum + ":" + name);
+ String resultCode = sendOneSiteWeibo(restTemplate, name, author, desc, "酸味书屋", bookNum, href);
+ log.debug(excuteNum + ":" + name + ":" + resultCode);
+ log.debug(excuteNum + ":resultCode=={\"code\":\"A00006\"}" + "{\"code\":\"A00006\"}".equals(resultCode));
+
+ if ("{\"code\":\"A00006\"}".equals(resultCode)) {
+ cacheUtil.set(BOOKNAME_CACHE_PREFIX + name, name, 60 * 60 * 24 * 30);
+ }
+ long realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ Thread.sleep(realSleepMillis);
+ }
+
+ }
+ isFind = match.find();
+ }
+
+
+ String forObject2 = forEntity2.getBody();
+ pattern = Pattern.compile("" +
+ "\\s* ((.*))
\\s*" +
+ "");
+ match = pattern.matcher(forObject2);
+ isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+
+ float score = Float.parseFloat(match.group(4));
+
+ if (score >= 7.0) {
+
+ String bookNum = match.group(1);
+ String href = "http://m.zinglizingli.xyz/" + bookNum + ".html";
+ String name = match.group(2);
+ if (!name.equals(cacheUtil.get(BOOKNAME_CACHE_PREFIX + name))) {
+ String author = match.group(3);
+ String desc = match.group(5);
+
+ String resultCode = sendOneSiteWeibo(restTemplate, name, author, desc, "喜羊羊小说网", bookNum, href);
+ if ("{\"code\":\"A00006\"}".equals(resultCode)) {
+ cacheUtil.set(BOOKNAME_CACHE_PREFIX + name, name, 60 * 60 * 24 * 30);
+ }
+
+ long realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ Thread.sleep(realSleepMillis);
+
+ }
+ }
+ isFind = match.find();
+ }
+
+
+ }
+ }
+
+ } catch (Exception e) {
+ log.error(e.getMessage(),e);
+
+ } finally {
+ isExcuting = false;
+ }
+
+ }
+
+ }
+*/
+ //19点到23点,1点到4点每隔50分钟执行一次,20本书*2分钟+空闲时间
+ //@Scheduled(cron = "0 */50 19-23,1-4 * * ?")
+
+ /* public void sendAtNight() throws InterruptedException, IOException {
+ if (!isExcuting) {
+ isExcuting = true;
+ log.info("sendAtNight定时器开始执行。。。。");
+ long sleepMillis = 1000 * 60 * 2;
+ sendAllSiteWeibo(sleepMillis);
+ Thread.sleep(1000 * 60 * 10);
+ isExcuting = false;
+ }
+
+
+ }*/
+
+
+ //6点到17点每隔1小时执行一次,20本书*5分钟+空闲时间
+ //@Scheduled(cron = "0 0 6-17/1 * * ?")
+ /* public void sendAtDayTime() throws InterruptedException, IOException {
+
+ if (!isExcuting) {
+ isExcuting = true;
+ log.info("sendAtDayTime定时器开始执行。。。。");
+ long sleepMillis = 1000 * 60 * 5;
+ sendAllSiteWeibo(sleepMillis);
+ Thread.sleep(1000 * 60 * 10);
+ isExcuting = false;
+ }
+
+ }*/
+
+ /*private void sendAllSiteWeibo(long sleepMillis) throws InterruptedException {
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+ //分享酸味书屋
+ String url = "http://www.zinglizingli.xyz/paihangbang_lastupdate/1.html";
+
+ //分享喜羊羊小说网
+ String url2 = "http://m.zinglizingli.xyz/class/0/1.html";
+
+ ResponseEntity forEntity = restTemplate.getForEntity(url, String.class);
+ ResponseEntity forEntity2 = restTemplate.getForEntity(url2, String.class);
+
+ String forObject = forEntity.getBody();
+ Pattern pattern = Pattern.compile("\n" +
+ "(.*) \n" +
+ "(.*) \n" +
+ "(.*)\\.\\.\\. \n" +
+ "(\\d*) 人在看 \n" +
+ " ");
+ Matcher match = pattern.matcher(forObject);
+ boolean isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+
+ int lookNum = Integer.parseInt(match.group(5));
+ if (lookNum > 5000) {
+ String bookNum = match.group(1);
+ String href = "http://www.zinglizingli.xyz/" + bookNum;
+ String name = match.group(2);
+ String author = match.group(3);
+ String desc = match.group(4);
+ sendOneSiteWeibo(restTemplate, name, author, desc, "酸味书屋", bookNum, href);
+ long realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ Thread.sleep(realSleepMillis);
+ }
+
+ isFind = match.find();
+
+ }
+ }
+
+
+ String forObject2 = forEntity2.getBody();
+ pattern = Pattern.compile("" +
+ "\\s* ((.*))
\\s*" +
+ "");
+ match = pattern.matcher(forObject2);
+ isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+
+ float score = Float.parseFloat(match.group(4));
+
+ if (score >= 7.0) {
+
+ String bookNum = match.group(1);
+ String href = "http://m.zinglizingli.xyz/" + bookNum;
+ String name = match.group(2);
+ String author = match.group(3);
+ String desc = match.group(5);
+
+ sendOneSiteWeibo(restTemplate, name, author, desc, "喜羊羊小说网", bookNum, href);
+
+ long realSleepMillis = sleepMillis + (new Random().nextInt(15)) * 60 * 1000;
+ Thread.sleep(realSleepMillis);
+ }
+
+ isFind = match.find();
+
+
+ }
+ }
+ }*/
+
+
+ public static void main(String[] args) throws Exception {
+ RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
+ //分享酸味书屋
+ String url = "http://www.zinglizingli.xyz/paihangbang_lastupdate/1.html";
+ ResponseEntity forEntity = restTemplate.getForEntity(url, String.class);
+ String forObject = forEntity.getBody();
+ Pattern pattern = Pattern.compile("\n" +
+ "(.*) \n" +
+ "(.*) \n" +
+ "(.*)\\.\\.\\. \n" +
+ "\\d* 人在看 \n" +
+ " ");
+ Matcher match = pattern.matcher(forObject);
+ boolean isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+ String bookNum = match.group(1);
+ String href = "http://www.zinglizingli.xyz/" + bookNum;
+ String name = match.group(2);
+ String author = match.group(3);
+ String desc = match.group(4);
+
+
+ isFind = match.find();
+
+ }
+ }
+
+ //分享喜羊羊小说网
+ url = "http://m.zinglizingli.xyz/class/0/1.html";
+ forEntity = restTemplate.getForEntity(url, String.class);
+ forObject = forEntity.getBody();
+ pattern = Pattern.compile("" +
+ "\\s* ((.*))
\\s*" +
+ "");
+ match = pattern.matcher(forObject);
+ isFind = match.find();
+ if (isFind) {
+ while (isFind) {
+ String bookNum = match.group(1);
+ String href = "http://m.zinglizingli.xyz/" + bookNum;
+ String name = match.group(2);
+ String author = match.group(3);
+ String desc = match.group(4);
+ // sendOneSiteWeibo(restTemplate, name, author, desc, "喜羊羊小说网", bookNum, href);
+
+
+ isFind = match.find();
+
+
+ }
+ }
+
+
+ }
+
+ private String sendOneSiteWeibo(RestTemplate template, String bookName, String indexName, String author, String desc, String wapName, String bookNum, String href) {
+ String baseUrl = "http://service.weibo.com/share/aj_share.php";
+ Map param = new HashMap<>();
+ String content = bookName + "小说最新章节列表," + bookName + "小说免费在线阅读," + bookName +
+ "小说TXT下载,尽在" + wapName +href+ "\n";
+ if(indexName != null){
+ content+=("最新章节:"+indexName+"\n");
+ }
+ content = content + "作者:"+(author.replace("作者:","")) + "\n";
+ content += ("简介:"+desc.replace("简介:",""));
+ param.put("content", content );
+ param.put("styleid", "1");
+ param.put("from", "share");
+ param.put("appkey", "2351975812");
+ param.put("refer", "http://www.zinglizingli.xyz/" + bookNum + "/");
+ param.put("url_type", "0");
+ param.put("visible", "0");
+ //byte[] bytes = sendPostRequest(baseUrl, param);
+
+
+ MultiValueMap map = new LinkedMultiValueMap<>();
+ map.setAll(param);
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Accept", "*/*");
+ headers.add("Accept-Encoding", "gzip, deflate");
+ headers.add("Accept-Language", "zh-CN,zh;q=0.9");
+ headers.add("Connection", "keep-alive");
+ headers.add("Content-Length", "1146");
+ headers.add("Content-Type", "application/x-www-form-urlencoded");
+
+ String[] cookieArr = cookieStr.split(";");
+ List cookies = Arrays.asList(cookieArr);
+ headers.put(HttpHeaders.COOKIE, cookies);
+
+ headers.add("Host", "service.weibo.com");
+ headers.add("Origin", "http://service.weibo.com");
+ headers.add("Referer", "http://service.weibo.com/share/share.php?appkey=2351975812&searchPic=true&title=%C2%A1%C2%BE%E4%BF%AE%E7%9C%9F%E8%81%8A%E5%A4%A9%E7%BE%A4%E6%9C%80%E6%96%B0%E7%AB%A0%E8%8A%82%E5%88%97%E8%A1%A8_%E4%BF%AE%E7%9C%9F%E8%81%8A%E5%A4%A9%E7%BE%A4%E6%9C%80%E6%96%B0%E7%AB%A0%E8%8A%82%E7%9B%AE%E5%BD%95_%E9%85%B8%E5%91%B3%E4%B9%A6%E5%B1%8B%C2%A1%C2%BF%E4%BF%AE%E7%9C%9F%E8%81%8A%E5%A4%A9%E7%BE%A4%E6%9C%80%E6%96%B0%E7%AB%A0%E8%8A%82%E7%94%B1%E7%BD%91%E5%8F%8B%E6%8F%90%E4%BE%9B%EF%BC%8C%E3%80%8A%E4%BF%AE%E7%9C%9F%E8%81%8A%E5%A4%A9%E7%BE%A4%E3%80%8B%E6%83%85%E8%8A%82%E8%B7%8C%E5%AE%95%E8%B5%B7%E4%BC%8F%E3%80%81%E6%89%A3%E4%BA%BA%E5%BF%83%E5%BC%A6%EF%BC%8C%E6%98%AF%E4%B8%80%E6%9C%AC%E6%83%85%E8%8A%82%E4%B8%8E%E6%96%87%E7%AC%94%E4%BF%B1%E4%BD%B3%E7%9A%84%E9%83%BD%E5%B8%82%E5%B0%8F%E8%AF%B4%E5%B0%8F%E8%AF%B4%EF%BC%8C%E9%85%B8%E5%91%B3%E4%B9%A6%E5%B1%8B%E5%85%8D%E8%B4%B9%E6%8F%90%E4%BE%9B%E5%94%90%E7%A0%96%E6%9C%80%E6%96%B0%E6%B8%85%E7%88%BD%E5%B9%B2%E5%87%80%E7%9A%84%E6%96%87%E5%AD%97%E7%AB%A0%E8%8A%82%E5%9C%A8%E7%BA%BF%E9%98%85%E8%AF%BB.&url=http%3A//www.zinglizingli.xyz/" + bookNum + "/");
+ headers.add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE");
+ headers.add("X-Requested-With", "XMLHttpRequest");
+ headers.add("Accept-Encoding", "gzip, deflate");
+ headers.add("Accept-Language", "zh-CN,zh;q=0.9");
+ headers.add("Connection", "keep-alive");
+ headers.add("Content-Length", "1146");
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ HttpEntity> request = new HttpEntity<>(map, headers);
+
+ ResponseEntity stringResponseEntity = template.postForEntity(baseUrl, request, String.class, map);
+
+ return stringResponseEntity.getBody();
+ }
+
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/utils/ContentFactory.java b/src/main/java/xyz/zinglizingli/search/utils/ContentFactory.java
new file mode 100644
index 0000000..fef13e9
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/utils/ContentFactory.java
@@ -0,0 +1,65 @@
+package xyz.zinglizingli.search.utils;
+
+import java.util.*;
+
+public class ContentFactory {
+
+
+ private static String[] hotWords = {"雪鹰领主是我吃西红柿写作的一本非常经典的玄幻小说,本站免费提供雪鹰领主最新最全的TXT全文小说阅读。",
+ "飞剑问道是我吃西红柿的经典仙侠小说作品,本站提供我吃西红柿TXT小说免费阅读。","" +
+ "终极美女保镖小说阅读,《终极美女保镖》情节跌宕起伏、扣人心弦,是一本情节与文笔俱佳的玄幻小说,本站免费提供终极美女保镖最新清爽干净的文字章节在线阅读。",
+ "一世倾城:冷宫弃妃,一世倾城:冷宫弃妃小说无弹窗阅读,一世倾城:冷宫弃妃小说无广告全文阅读,作者冷青衫",
+ "校花之贴身高手最新章节,VIP章节免费阅读,校花之贴身高手由寂无倾情打造。看精品小说,上看小说吧!",
+ "邪王追妻最新章节_邪王追妻免费全文阅读",
+ "《最强反派系统》免费阅读,最强反派系统小说最新章节免费阅读,VIP章节免费阅读。",
+ "大妖尊小说试阅读,大妖尊,大妖尊全文阅读,大妖尊最新章节",
+ "诡秘之主,诡秘之主小说阅读。玄幻小说诡秘之主由作家爱潜水的乌贼创作,看小说吧提供诡秘之主首发最新章节及章节列表,诡秘之主最新更新尽在看小说吧",
+ "全球高武,全球高武小说免费阅读。都市小说全球高武由作家老鹰吃小鸡创作,本站提供全球高武小说首发最新免费章节及章节列表,全球高武小说最新更新免费阅读","" +
+ "前任无双由作家跃千愁创作,前任无双小说免费阅读,无双首发最新章节及章节列表免费阅读,无弹窗、无广告小说免费月的",
+ "万古第一神小说是由作家风青阳所著的东方玄幻小说,本站提供万古第一神小说小说最新章节免费阅读",
+ "《剑来》小说是烽火戏诸侯在著作的武侠仙侠, 本站提供无广告、无弹窗的剑来小说最新章节全文免费阅读,请随时关注更新最快的小说阅读网看小说吧。",
+ "免费小说阅读,精彩免费小说最新章节尽在看小说吧,小说,小说网;网络小说;小说下载;小说txt,小说全文阅读,无弹窗广告尽在本站",
+ "看小说吧收集、整理和免费分享作者几人哀愁的最新免费小说:回到过去当女神最新目录列表,回到过去当女神小说是属于网友受欢迎的奇幻玄幻类型的小说。",
+ "大主宰无弹窗无广告最新免费章节由网友提供,《大主宰》小说情节跌宕起伏、扣人心弦:是一本情节与文笔俱佳的玄幻小说,看小说吧小说网免费大主宰最新免费的清爽干净的文字VIP章节在线阅读。",
+ "旋风少女小说最新免费章节由网友提供,《旋风少女》是一本受欢迎的情节和文笔俱佳的都市小说,旋风少女无弹窗无广告小说最新章节目录免费阅读,旋风少女VIP章节免费阅读!",
+ "斗破苍穹最新章节无弹窗是天蚕土豆倾力打造的一本非常耐读的小说,情节波澜起伏,由浅入深,层层推进,希望你能喜欢本书,支持天蚕土豆请收藏并推荐,斗破苍穹无弹窗最新免费章节目录免费提供"
+ ,"九星霸体诀是平凡魔术师写作的一本非常经典的玄幻小说,本站免费提供平凡魔术师最新最全的TXT全文小说阅读。",
+ "万古神帝是飞天鱼的经典仙侠小说作品,本站提供万古神帝TXT小说免费阅读。","" +
+ "无敌真寂寞小说阅读,《无敌真寂寞》情节跌宕起伏、扣人心弦,是一本情节与文笔俱佳的玄幻小说,本站免费提供无敌真寂寞最新清爽干净的文字章节在线阅读。",
+ "绝鼎丹尊,绝鼎丹尊小说无弹窗阅读,绝鼎丹尊小说无广告全文阅读,作者万古青莲",
+ "龙王传说最新章节,VIP章节免费阅读,龙王传说由唐家三少打造。看精品小说,上看小说吧!",
+ "人道至尊,人道至尊小说阅读。玄幻小说人道至尊由作家宅猪创作,看小说吧提供人道至尊首发最新章节及章节列表,人道至尊最新更新尽在看小说吧小说网",
+ "还是地球人狠,还是地球人狠免费阅读。都市小说全球高武由作家剑舞秀创作,本站提供还是地球人狠小说首发最新免费章节及章节列表,全球高武小说最新更新免费阅读","" +
+ "《求魔》小说是在耳根著作的武侠仙侠, 本站提供无广告、无弹窗的求魔小说最新章节全文免费阅读,请随时关注更新最快的小说阅读网看小说吧。",
+ "看小说吧收集、整理和免费分享作者唐家三少的最新免费小说:天火大道最新目录列表,天火大道小说是属于网友受欢迎的奇幻玄幻类型的小说。",
+ "饲养全人类无弹窗无广告最新免费章节由网友提供,《饲养全人类》小说情节跌宕起伏、扣人心弦:是一本情节与文笔俱佳的玄幻小说,看小说吧小说网免费饲养全人类最新免费的清爽干净的文字VIP章节在线阅读。",
+ "方外:消失的八门小说最新免费章节由网友提供,《方外:消失的八门》是一本受欢迎的情节和文笔俱佳的都市小说,方外:消失的八门无弹窗无广告小说最新章节目录免费阅读,方外:消失的八门VIP章节免费阅读!",
+ "武林赘婿最新章节无弹窗是左山左行倾力打造的一本非常耐读的小说,情节波澜起伏,由浅入深,层层推进,希望你能喜欢本书,支持武林赘婿请收藏并推荐,武林赘婿无弹窗最新免费章节目录免费提供"};
+
+
+
+ public static Map giveRandomContent(){
+ Map contentMap = new HashMap<>();
+ int size = 0;
+
+ for(int i = 0 ; i < hotWords.length ; i++){
+ if(size >= 18){
+ break;
+ }
+ String value = hotWords[new Random().nextInt(hotWords.length)];
+ if(contentMap.values().contains(value)){
+ continue;
+ }
+ contentMap.put("hotWord_"+size,value);
+ size++;
+ }
+ if(size < 18){
+ for(int i = 0 ; i< 18 - size ; i++){
+ contentMap.put("hotWord_"+size,hotWords[new Random().nextInt(hotWords.length)]);
+ size++;
+ }
+ }
+ return contentMap;
+
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/utils/NumberUtil.java b/src/main/java/xyz/zinglizingli/search/utils/NumberUtil.java
new file mode 100644
index 0000000..101ebff
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/utils/NumberUtil.java
@@ -0,0 +1,117 @@
+package xyz.zinglizingli.search.utils;
+
+
+public class NumberUtil {
+
+ public static int solve(String s) {
+ int i = s.indexOf("万");
+ if (i != -1) {
+ int l = solve(s.substring(0, i));
+ int r = solve(s.substring(i+1));
+ return l*10000 + r;
+ }
+ i = s.indexOf("千");
+ if (i != -1) {
+ int l = solve(s.substring(0, i));
+ int r = solve(s.substring(i+1));
+ return l*1000 + r;
+ }
+ i = s.indexOf("百");
+ if (i != -1) {
+ int l = solve(s.substring(0, i));
+ int r = solve(s.substring(i+1));
+ return l*100 + r;
+ }
+ i = s.indexOf("十");
+ if (i != -1) {
+ int l = solve(s.substring(0, i));
+ if (l == 0)
+ l = 1;
+ int r = solve(s.substring(i+1));
+ return l*10 + r;
+ }
+ i = s.indexOf("零");
+ if (i != -1) {
+ int l = solve(s.substring(0, i));
+ int r = solve(s.substring(i+1));
+ return l + r;
+ }
+ i = 0;
+ switch (s) {
+ case "九":
+ return 9;
+ case "八":
+ return 8;
+ case "七":
+ return 7;
+ case "六":
+ return 6;
+ case "五":
+ return 5;
+ case "四":
+ return 4;
+ case "三":
+ return 3;
+ case "二":
+ return 2;
+ case "一":
+ return 1;
+ }
+ return 0;
+ }
+ public static String solve(int n) {
+ int w = n / 10000, q = n / 1000, b = n / 100, s = n / 10;
+ if (w > 0) {
+ String l = solve(n/10000);
+ String r = solve(n%10000);
+ if ((n%10000)/1000 == 0)
+ r = "零" + r;
+ return l + "万" + r;
+ }
+ if (q > 0) {
+ String l = solve(n/1000);
+ String r = solve(n%1000);
+ if ((n%1000)/100 == 0)
+ r = "零" + r;
+ return l + "千" + r;
+ }
+ if (b > 0) {
+ String l = solve(n/100);
+ String r = solve(n%100);
+ if ((n%100)/10 == 0)
+ r = "零" + r;
+ return l + "百" + r;
+ }
+ if (s > 0) {
+ String l = solve(n/10);
+ String r = solve(n%10);
+ return l + "十" + r;
+ }
+ switch (n){
+ case 1:
+ return "一";
+ case 2:
+ return "二";
+ case 3:
+ return "三";
+ case 4:
+ return "四";
+ case 5:
+ return "五";
+ case 6:
+ return "六";
+ case 7:
+ return "七";
+ case 8:
+ return "八";
+ case 9:
+ return "九";
+ }
+ return "";
+ }
+
+ public static void main(String[] args) {
+ System.out.println(solve("五百七十八"));
+ System.out.println(solve(3786));
+ }
+}
diff --git a/src/main/java/xyz/zinglizingli/search/utils/RestTemplateUtil.java b/src/main/java/xyz/zinglizingli/search/utils/RestTemplateUtil.java
new file mode 100644
index 0000000..f6322a6
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/utils/RestTemplateUtil.java
@@ -0,0 +1,30 @@
+package xyz.zinglizingli.search.utils;
+
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+public class RestTemplateUtil {
+
+
+ public static RestTemplate getInstance(String charset) {
+ HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
+ httpRequestFactory.setConnectionRequestTimeout(3000);
+ httpRequestFactory.setConnectTimeout(3000);
+ httpRequestFactory.setReadTimeout(10000);
+ RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
+ List> list = restTemplate.getMessageConverters();
+ for (HttpMessageConverter> httpMessageConverter : list) {
+ if(httpMessageConverter instanceof StringHttpMessageConverter) {
+ ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(charset));
+ break;
+ }
+ }
+ return restTemplate;
+ }
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/utils/SpringUtil.java b/src/main/java/xyz/zinglizingli/search/utils/SpringUtil.java
new file mode 100644
index 0000000..d2baf8c
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/utils/SpringUtil.java
@@ -0,0 +1,54 @@
+package xyz.zinglizingli.search.utils;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.io.UnsupportedEncodingException;
+
+
+@Component
+public class SpringUtil implements ApplicationContextAware {
+
+
+ public static void main(String[] args) {
+ String a = "���";
+ try {
+ String b = new String(a.getBytes("ISO-8859-1"),"gbk");
+ System.out.println(b);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static ApplicationContext applicationContext;
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (SpringUtil.applicationContext == null) {
+ SpringUtil.applicationContext = applicationContext;
+ }
+ }
+
+ // 获取applicationContext
+ public static ApplicationContext getApplicationContext() {
+ return applicationContext;
+ }
+
+ // 通过name获取 Bean.
+ public static Object getBean(String name) {
+ return getApplicationContext().getBean(name);
+ }
+
+ // 通过class获取Bean.
+ public static T getBean(Class clazz) {
+ return getApplicationContext().getBean(clazz);
+ }
+
+ // 通过name,以及Clazz返回指定的Bean
+ public static T getBean(String name, Class clazz) {
+ return getApplicationContext().getBean(name, clazz);
+ }
+
+}
diff --git a/src/main/java/xyz/zinglizingli/search/web/IndexController.java b/src/main/java/xyz/zinglizingli/search/web/IndexController.java
new file mode 100644
index 0000000..da662a8
--- /dev/null
+++ b/src/main/java/xyz/zinglizingli/search/web/IndexController.java
@@ -0,0 +1,22 @@
+package xyz.zinglizingli.search.web;
+
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import xyz.zinglizingli.search.utils.ContentFactory;
+
+import java.util.Set;
+
+@Controller
+@RequestMapping
+public class IndexController {
+
+
+
+ @RequestMapping(value = {"/index.html","/"})
+ public String index(ModelMap modelMap){
+ modelMap.put("hotBookList", ContentFactory.giveRandomContent());
+ return "index";
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..ad7782e
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,66 @@
+server:
+ port: 80
+
+spring:
+ datasource:
+ url: jdbc:mysql://127.0.0.1:3306/books?useUnicode=true&characterEncoding=utf-8
+ username: books
+ password: books
+ cache:
+ ehcache:
+ config: classpath:ehcache.xml
+ thymeleaf:
+ mode: LEGACYHTML5 #去除thymeleaf的html严格校验thymeleaf.mode=LEGACYHTML5
+ cache: true # 是否开启模板缓存,默认true,建议在开发时关闭缓存,不然没法看到实时页面
+ freemarker:
+ template-loader-path: classpath:/templates #设定thymeleaf文件路径 默认为src/main/resources/templatestemplate-loader-path=classpath:/templates
+ charset: UTF-8 # 模板编码
+ #邮箱服务器
+ mail:
+ host: smtp.163.com
+ #邮箱账户
+ username:
+ #你的QQ邮箱第三方授权码
+ password:
+ #编码类型
+ default-encoding: UTF-8
+ port: 465
+ properties:
+ mail:
+ smtp:
+ auth: true
+ starttls:
+ enable: true
+ required: rue
+ socketFactory:
+ port: 465
+ class: javax.net.ssl.SSLSocketFactory
+ fallback: false
+
+
+
+
+# mvc:
+# static-path-pattern: /static/** #设定静态文件路径,js,css等
+mybatis:
+ mapper-locations: classpath:mybatis/mapping/*.xml
+ type-aliases-package: xyz.zinglizingli.books.po
+
+
+
+search:
+ schedule:
+ isRunExcute: 0;
+
+
+logging:
+ config: classpath:logback-boot.xml
+
+
+baidu:
+ record:
+ ids: 999999,888888
+
+
+browser:
+ cookie: SINAGLOBAL=5945695441587.724.1559298271897; __guid=109181959.2094437407894937900.1565875017257.2095; un=13560421324; _s_tentry=-; Apache=8157572449986.1455.1566918991846; ULV=1566918991855:7:6:1:8157572449986.1455.1566918991846:1566086532731; login_sid_t=0cc80b9f5ea5f473e83fce3054291c03; cross_origin_proto=SSL; un=13560421324; YF-Widget-G0=4aade6ec367f09ec0a5eec921227137f; WBtopGlobal_register_version=307744aa77dd5677; SSOLoginState=1566928337; wvr=6; UOR=,,www.zinglizingli.xyz; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WFRg9065OjUyD0aaGsKRxPW5JpX5KMhUgL.Fo-f1hB7SKMp1h52dJLoI0qLxK-L1KqL1-eLxKMLB.-L122LxKMLB.-L122LxK-LBo5L12qLxKnLB-qLBoBLxKMLB.BL1K2t; ALF=1599046395; SCF=AsBEGOtiUG1hPLyZCxI1FunZd9Hg9hWWkgyzcAZjG6AxOiKPAEM99ZxY8qofeWw3xoU_Wh3OqNzt4BSkCAyD_8o.; SUB=_2A25waj8tDeRhGeNL41YR9SnNwzyIHXVTHhflrDV8PUNbmtANLXXAkW9NSM603mvU3tqplLCrqvedw1Q29U_TkxRA; SUHB=0xnyhR4nBtqt14; monitor_count=2; webim_unReadCount=%7B%22time%22%3A1567510495487%2C%22dm_pub_total%22%3A2%2C%22chat_group_client%22%3A0%2C%22allcountNum%22%3A36%2C%22msgbox%22%3A0%7D
\ No newline at end of file
diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml
new file mode 100644
index 0000000..6ccf83d
--- /dev/null
+++ b/src/main/resources/ehcache.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/logback-boot.xml b/src/main/resources/logback-boot.xml
new file mode 100644
index 0000000..7f02933
--- /dev/null
+++ b/src/main/resources/logback-boot.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+
+ UTF-8
+
+
+
+
+
+
+
+
+ logs/debug.log
+
+
+
+
+
+ logs/debug.%d.%i.log
+
+ 30
+
+
+ 10MB
+
+
+
+
+
+ %d %p (%file:%line\)- %m%n
+
+
+ UTF-8
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/generatorConfig.xml b/src/main/resources/mybatis/generatorConfig.xml
new file mode 100644
index 0000000..25a1408
--- /dev/null
+++ b/src/main/resources/mybatis/generatorConfig.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/BookContentMapper.xml b/src/main/resources/mybatis/mapping/BookContentMapper.xml
new file mode 100644
index 0000000..1eb1d04
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/BookContentMapper.xml
@@ -0,0 +1,228 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, book_id, index_id, index_num, content
+
+
+ select
+
+ distinct
+
+
+ from book_content
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from book_content
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book_content
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book_content
+
+
+
+
+
+ insert into book_content (id, book_id, index_id,
+ index_num, content)
+ values (#{id,jdbcType=BIGINT}, #{bookId,jdbcType=BIGINT}, #{indexId,jdbcType=BIGINT},
+ #{indexNum,jdbcType=INTEGER}, #{content,jdbcType=VARCHAR})
+
+
+ insert into book_content
+
+
+ id,
+
+
+ book_id,
+
+
+ index_id,
+
+
+ index_num,
+
+
+ content,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{bookId,jdbcType=BIGINT},
+
+
+ #{indexId,jdbcType=BIGINT},
+
+
+ #{indexNum,jdbcType=INTEGER},
+
+
+ #{content,jdbcType=VARCHAR},
+
+
+
+
+ select count(*) from book_content
+
+
+
+
+
+ update book_content
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ book_id = #{record.bookId,jdbcType=BIGINT},
+
+
+ index_id = #{record.indexId,jdbcType=BIGINT},
+
+
+ index_num = #{record.indexNum,jdbcType=INTEGER},
+
+
+ content = #{record.content,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ update book_content
+ set id = #{record.id,jdbcType=BIGINT},
+ book_id = #{record.bookId,jdbcType=BIGINT},
+ index_id = #{record.indexId,jdbcType=BIGINT},
+ index_num = #{record.indexNum,jdbcType=INTEGER},
+ content = #{record.content,jdbcType=VARCHAR}
+
+
+
+
+
+ update book_content
+
+
+ book_id = #{bookId,jdbcType=BIGINT},
+
+
+ index_id = #{indexId,jdbcType=BIGINT},
+
+
+ index_num = #{indexNum,jdbcType=INTEGER},
+
+
+ content = #{content,jdbcType=VARCHAR},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update book_content
+ set book_id = #{bookId,jdbcType=BIGINT},
+ index_id = #{indexId,jdbcType=BIGINT},
+ index_num = #{indexNum,jdbcType=INTEGER},
+ content = #{content,jdbcType=VARCHAR}
+ where id = #{id,jdbcType=BIGINT}
+
+
+
+
+ insert into book_content (book_id, index_num, content)
+ values
+
+
+ #{item.bookId,jdbcType=VARCHAR},
+ #{item.indexNum,jdbcType=VARCHAR},
+ #{item.content,jdbcType=VARCHAR},
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/BookIndexMapper.xml b/src/main/resources/mybatis/mapping/BookIndexMapper.xml
new file mode 100644
index 0000000..ce34606
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/BookIndexMapper.xml
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, book_id, index_num, index_name
+
+
+ select
+
+ distinct
+
+
+ from book_index
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from book_index
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book_index
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book_index
+
+
+
+
+
+ insert into book_index (id, book_id, index_num,
+ index_name)
+ values (#{id,jdbcType=BIGINT}, #{bookId,jdbcType=BIGINT}, #{indexNum,jdbcType=INTEGER},
+ #{indexName,jdbcType=VARCHAR})
+
+
+ insert into book_index
+
+
+ id,
+
+
+ book_id,
+
+
+ index_num,
+
+
+ index_name,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{bookId,jdbcType=BIGINT},
+
+
+ #{indexNum,jdbcType=INTEGER},
+
+
+ #{indexName,jdbcType=VARCHAR},
+
+
+
+
+ select count(*) from book_index
+
+
+
+
+
+ update book_index
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ book_id = #{record.bookId,jdbcType=BIGINT},
+
+
+ index_num = #{record.indexNum,jdbcType=INTEGER},
+
+
+ index_name = #{record.indexName,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ update book_index
+ set id = #{record.id,jdbcType=BIGINT},
+ book_id = #{record.bookId,jdbcType=BIGINT},
+ index_num = #{record.indexNum,jdbcType=INTEGER},
+ index_name = #{record.indexName,jdbcType=VARCHAR}
+
+
+
+
+
+ update book_index
+
+
+ book_id = #{bookId,jdbcType=BIGINT},
+
+
+ index_num = #{indexNum,jdbcType=INTEGER},
+
+
+ index_name = #{indexName,jdbcType=VARCHAR},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update book_index
+ set book_id = #{bookId,jdbcType=BIGINT},
+ index_num = #{indexNum,jdbcType=INTEGER},
+ index_name = #{indexName,jdbcType=VARCHAR}
+ where id = #{id,jdbcType=BIGINT}
+
+
+
+
+ insert into book_index (book_id, index_num, index_name)
+ values
+
+
+ #{item.bookId,jdbcType=VARCHAR},
+ #{item.indexNum,jdbcType=VARCHAR},
+ #{item.indexName,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ select index_name from book_index where book_id = #{bookId,jdbcType=BIGINT} order by index_num desc limit 1
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/BookMapper.xml b/src/main/resources/mybatis/mapping/BookMapper.xml
new file mode 100644
index 0000000..b979dcf
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/BookMapper.xml
@@ -0,0 +1,373 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, catId, pic_url, book_name, author, book_desc, score, book_status, visit_count,
+ update_time,soft_cat,soft_tag
+
+
+ select
+
+ distinct
+
+
+ from book
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from book
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from book
+
+
+
+
+
+ insert into book (id, catId, pic_url,
+ book_name, author, book_desc,
+ score, book_status, visit_count,
+ update_time)
+ values (#{id,jdbcType=BIGINT}, #{catid,jdbcType=INTEGER}, #{picUrl,jdbcType=VARCHAR},
+ #{bookName,jdbcType=VARCHAR}, #{author,jdbcType=VARCHAR}, #{bookDesc,jdbcType=VARCHAR},
+ #{score,jdbcType=REAL}, #{bookStatus,jdbcType=VARCHAR}, #{visitCount,jdbcType=BIGINT},
+ #{updateTime,jdbcType=TIMESTAMP})
+
+
+ insert into book
+
+
+ id,
+
+
+ catId,
+
+
+ pic_url,
+
+
+ book_name,
+
+
+ author,
+
+
+ book_desc,
+
+
+ score,
+
+
+ book_status,
+
+
+ visit_count,
+
+
+ update_time,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{catid,jdbcType=INTEGER},
+
+
+ #{picUrl,jdbcType=VARCHAR},
+
+
+ #{bookName,jdbcType=VARCHAR},
+
+
+ #{author,jdbcType=VARCHAR},
+
+
+ #{bookDesc,jdbcType=VARCHAR},
+
+
+ #{score,jdbcType=REAL},
+
+
+ #{bookStatus,jdbcType=VARCHAR},
+
+
+ #{visitCount,jdbcType=BIGINT},
+
+
+ #{updateTime,jdbcType=TIMESTAMP},
+
+
+
+
+ select count(*) from book
+
+
+
+
+
+ update book
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ catId = #{record.catid,jdbcType=INTEGER},
+
+
+ pic_url = #{record.picUrl,jdbcType=VARCHAR},
+
+
+ book_name = #{record.bookName,jdbcType=VARCHAR},
+
+
+ author = #{record.author,jdbcType=VARCHAR},
+
+
+ book_desc = #{record.bookDesc,jdbcType=VARCHAR},
+
+
+ score = #{record.score,jdbcType=REAL},
+
+
+ book_status = #{record.bookStatus,jdbcType=VARCHAR},
+
+
+ visit_count = #{record.visitCount,jdbcType=BIGINT},
+
+
+ update_time = #{record.updateTime,jdbcType=TIMESTAMP},
+
+
+
+
+
+
+
+ update book
+ set id = #{record.id,jdbcType=BIGINT},
+ catId = #{record.catid,jdbcType=INTEGER},
+ pic_url = #{record.picUrl,jdbcType=VARCHAR},
+ book_name = #{record.bookName,jdbcType=VARCHAR},
+ author = #{record.author,jdbcType=VARCHAR},
+ book_desc = #{record.bookDesc,jdbcType=VARCHAR},
+ score = #{record.score,jdbcType=REAL},
+ book_status = #{record.bookStatus,jdbcType=VARCHAR},
+ visit_count = #{record.visitCount,jdbcType=BIGINT},
+ update_time = #{record.updateTime,jdbcType=TIMESTAMP}
+
+
+
+
+
+ update book
+
+
+ catId = #{catid,jdbcType=INTEGER},
+
+
+ pic_url = #{picUrl,jdbcType=VARCHAR},
+
+
+ book_name = #{bookName,jdbcType=VARCHAR},
+
+
+ author = #{author,jdbcType=VARCHAR},
+
+
+ book_desc = #{bookDesc,jdbcType=VARCHAR},
+
+
+ score = #{score,jdbcType=REAL},
+
+
+ book_status = #{bookStatus,jdbcType=VARCHAR},
+
+
+ visit_count = #{visitCount,jdbcType=BIGINT},
+
+
+ update_time = #{updateTime,jdbcType=TIMESTAMP},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update book
+ set catId = #{catid,jdbcType=INTEGER},
+ pic_url = #{picUrl,jdbcType=VARCHAR},
+ book_name = #{bookName,jdbcType=VARCHAR},
+ author = #{author,jdbcType=VARCHAR},
+ book_desc = #{bookDesc,jdbcType=VARCHAR},
+ score = #{score,jdbcType=REAL},
+ book_status = #{bookStatus,jdbcType=VARCHAR},
+ visit_count = #{visitCount,jdbcType=BIGINT},
+ update_time = #{updateTime,jdbcType=TIMESTAMP}
+ where id = #{id,jdbcType=BIGINT}
+
+
+
+
+ select book.id,book.catId,book.book_name,book.pic_url,book.author,book.book_desc,
+ book.score,book.book_status,book.update_time,book.soft_cat,book.soft_tag
+ from book
+
+ inner join user_ref_book on book.id = user_ref_book.book_id
+
+
+
+ AND user_ref_book.user_id = #{userId,jdbcType=BIGINT}
+
+
+
+ AND book.id in (${ids})
+
+
+ AND book.soft_cat = #{softCat,jdbcType=INTEGER}
+
+
+
+ AND book.catId = #{catId,jdbcType=INTEGER}
+
+
+
+ AND book.catId ]]> 8
+
+
+
+
+ AND book.soft_tag like concat('%',#{softTag,jdbcType=VARCHAR},'%')
+
+
+
+ AND (book.book_name like concat('%',#{keyword,jdbcType=VARCHAR},'%') or book.author like
+ concat('%',#{keyword,jdbcType=VARCHAR},'%'))
+
+
+ AND book.book_status = #{bookStatus,jdbcType=VARCHAR}
+
+
+
+
+
+
+ update book set visit_count = visit_count + 1
+ where id = #{bookId,jdbcType=BIGINT}
+
+
+
+
+ select id,book_name,book_desc,author from book order by rand() limit 1
+
+
+
+
+
+ select id,book_name,book_desc,author from book
+
+
+ #{item}
+
+
+ order by rand() desc limit 1
+
+
+
+
+
+ select id from book ORDER BY update_time desc limit 30
+
+
+
+ select id from book/* where book_status like '%完成%'*/
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/CategoryMapper.xml b/src/main/resources/mybatis/mapping/CategoryMapper.xml
new file mode 100644
index 0000000..0eb67db
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/CategoryMapper.xml
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, name, sort, get_url, req_url
+
+
+ select
+
+ distinct
+
+
+ from category
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from category
+ where id = #{id,jdbcType=INTEGER}
+
+
+ delete from category
+ where id = #{id,jdbcType=INTEGER}
+
+
+ delete from category
+
+
+
+
+
+ insert into category (id, name, sort,
+ get_url, req_url)
+ values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{sort,jdbcType=TINYINT},
+ #{getUrl,jdbcType=VARCHAR}, #{reqUrl,jdbcType=VARCHAR})
+
+
+ insert into category
+
+
+ id,
+
+
+ name,
+
+
+ sort,
+
+
+ get_url,
+
+
+ req_url,
+
+
+
+
+ #{id,jdbcType=INTEGER},
+
+
+ #{name,jdbcType=VARCHAR},
+
+
+ #{sort,jdbcType=TINYINT},
+
+
+ #{getUrl,jdbcType=VARCHAR},
+
+
+ #{reqUrl,jdbcType=VARCHAR},
+
+
+
+
+ select count(*) from category
+
+
+
+
+
+ update category
+
+
+ id = #{record.id,jdbcType=INTEGER},
+
+
+ name = #{record.name,jdbcType=VARCHAR},
+
+
+ sort = #{record.sort,jdbcType=TINYINT},
+
+
+ get_url = #{record.getUrl,jdbcType=VARCHAR},
+
+
+ req_url = #{record.reqUrl,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ update category
+ set id = #{record.id,jdbcType=INTEGER},
+ name = #{record.name,jdbcType=VARCHAR},
+ sort = #{record.sort,jdbcType=TINYINT},
+ get_url = #{record.getUrl,jdbcType=VARCHAR},
+ req_url = #{record.reqUrl,jdbcType=VARCHAR}
+
+
+
+
+
+ update category
+
+
+ name = #{name,jdbcType=VARCHAR},
+
+
+ sort = #{sort,jdbcType=TINYINT},
+
+
+ get_url = #{getUrl,jdbcType=VARCHAR},
+
+
+ req_url = #{reqUrl,jdbcType=VARCHAR},
+
+
+ where id = #{id,jdbcType=INTEGER}
+
+
+ update category
+ set name = #{name,jdbcType=VARCHAR},
+ sort = #{sort,jdbcType=TINYINT},
+ get_url = #{getUrl,jdbcType=VARCHAR},
+ req_url = #{reqUrl,jdbcType=VARCHAR}
+ where id = #{id,jdbcType=INTEGER}
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/ScreenBulletMapper.xml b/src/main/resources/mybatis/mapping/ScreenBulletMapper.xml
new file mode 100644
index 0000000..9594d99
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/ScreenBulletMapper.xml
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, content_id, screen_bullet, create_time
+
+
+ select
+
+ distinct
+
+
+ from screen_bullet
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from screen_bullet
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from screen_bullet
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from screen_bullet
+
+
+
+
+
+ insert into screen_bullet (id, content_id, screen_bullet,
+ create_time)
+ values (#{id,jdbcType=BIGINT}, #{contentId,jdbcType=BIGINT}, #{screenBullet,jdbcType=VARCHAR},
+ #{createTime,jdbcType=TIMESTAMP})
+
+
+ insert into screen_bullet
+
+
+ id,
+
+
+ content_id,
+
+
+ screen_bullet,
+
+
+ create_time,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{contentId,jdbcType=BIGINT},
+
+
+ #{screenBullet,jdbcType=VARCHAR},
+
+
+ #{createTime,jdbcType=TIMESTAMP},
+
+
+
+
+ select count(*) from screen_bullet
+
+
+
+
+
+ update screen_bullet
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ content_id = #{record.contentId,jdbcType=BIGINT},
+
+
+ screen_bullet = #{record.screenBullet,jdbcType=VARCHAR},
+
+
+ create_time = #{record.createTime,jdbcType=TIMESTAMP},
+
+
+
+
+
+
+
+ update screen_bullet
+ set id = #{record.id,jdbcType=BIGINT},
+ content_id = #{record.contentId,jdbcType=BIGINT},
+ screen_bullet = #{record.screenBullet,jdbcType=VARCHAR},
+ create_time = #{record.createTime,jdbcType=TIMESTAMP}
+
+
+
+
+
+ update screen_bullet
+
+
+ content_id = #{contentId,jdbcType=BIGINT},
+
+
+ screen_bullet = #{screenBullet,jdbcType=VARCHAR},
+
+
+ create_time = #{createTime,jdbcType=TIMESTAMP},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update screen_bullet
+ set content_id = #{contentId,jdbcType=BIGINT},
+ screen_bullet = #{screenBullet,jdbcType=VARCHAR},
+ create_time = #{createTime,jdbcType=TIMESTAMP}
+ where id = #{id,jdbcType=BIGINT}
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/UserMapper.xml b/src/main/resources/mybatis/mapping/UserMapper.xml
new file mode 100644
index 0000000..44384ba
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/UserMapper.xml
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, login_name, password
+
+
+ select
+
+ distinct
+
+
+ from user
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from user
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from user
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from user
+
+
+
+
+
+ insert into user (id, login_name, password
+ )
+ values (#{id,jdbcType=BIGINT}, #{loginName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}
+ )
+
+
+ insert into user
+
+
+ id,
+
+
+ login_name,
+
+
+ password,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{loginName,jdbcType=VARCHAR},
+
+
+ #{password,jdbcType=VARCHAR},
+
+
+
+
+ select count(*) from user
+
+
+
+
+
+ update user
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ login_name = #{record.loginName,jdbcType=VARCHAR},
+
+
+ password = #{record.password,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ update user
+ set id = #{record.id,jdbcType=BIGINT},
+ login_name = #{record.loginName,jdbcType=VARCHAR},
+ password = #{record.password,jdbcType=VARCHAR}
+
+
+
+
+
+ update user
+
+
+ login_name = #{loginName,jdbcType=VARCHAR},
+
+
+ password = #{password,jdbcType=VARCHAR},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update user
+ set login_name = #{loginName,jdbcType=VARCHAR},
+ password = #{password,jdbcType=VARCHAR}
+ where id = #{id,jdbcType=BIGINT}
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapping/UserRefBookMapper.xml b/src/main/resources/mybatis/mapping/UserRefBookMapper.xml
new file mode 100644
index 0000000..89c23f8
--- /dev/null
+++ b/src/main/resources/mybatis/mapping/UserRefBookMapper.xml
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, user_id, book_id
+
+
+ select
+
+ distinct
+
+
+ from user_ref_book
+
+
+
+
+ order by ${orderByClause}
+
+
+
+ select
+
+ from user_ref_book
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from user_ref_book
+ where id = #{id,jdbcType=BIGINT}
+
+
+ delete from user_ref_book
+
+
+
+
+
+ insert into user_ref_book (id, user_id, book_id
+ )
+ values (#{id,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{bookId,jdbcType=BIGINT}
+ )
+
+
+ insert into user_ref_book
+
+
+ id,
+
+
+ user_id,
+
+
+ book_id,
+
+
+
+
+ #{id,jdbcType=BIGINT},
+
+
+ #{userId,jdbcType=BIGINT},
+
+
+ #{bookId,jdbcType=BIGINT},
+
+
+
+
+ select count(*) from user_ref_book
+
+
+
+
+
+ update user_ref_book
+
+
+ id = #{record.id,jdbcType=BIGINT},
+
+
+ user_id = #{record.userId,jdbcType=BIGINT},
+
+
+ book_id = #{record.bookId,jdbcType=BIGINT},
+
+
+
+
+
+
+
+ update user_ref_book
+ set id = #{record.id,jdbcType=BIGINT},
+ user_id = #{record.userId,jdbcType=BIGINT},
+ book_id = #{record.bookId,jdbcType=BIGINT}
+
+
+
+
+
+ update user_ref_book
+
+
+ user_id = #{userId,jdbcType=BIGINT},
+
+
+ book_id = #{bookId,jdbcType=BIGINT},
+
+
+ where id = #{id,jdbcType=BIGINT}
+
+
+ update user_ref_book
+ set user_id = #{userId,jdbcType=BIGINT},
+ book_id = #{bookId,jdbcType=BIGINT}
+ where id = #{id,jdbcType=BIGINT}
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/HotBook.apk b/src/main/resources/static/HotBook.apk
new file mode 100644
index 0000000..346fb9a
Binary files /dev/null and b/src/main/resources/static/HotBook.apk differ
diff --git a/src/main/resources/static/IMG_1470.JPG b/src/main/resources/static/IMG_1470.JPG
new file mode 100644
index 0000000..26304c5
Binary files /dev/null and b/src/main/resources/static/IMG_1470.JPG differ
diff --git a/src/main/resources/static/baidu_verify_ANtJi2eSPQ.html b/src/main/resources/static/baidu_verify_ANtJi2eSPQ.html
new file mode 100644
index 0000000..494b211
--- /dev/null
+++ b/src/main/resources/static/baidu_verify_ANtJi2eSPQ.html
@@ -0,0 +1 @@
+ANtJi2eSPQ
\ No newline at end of file
diff --git a/src/main/resources/static/baidu_verify_Ep8xaWQJAI.html b/src/main/resources/static/baidu_verify_Ep8xaWQJAI.html
new file mode 100644
index 0000000..98d54f8
--- /dev/null
+++ b/src/main/resources/static/baidu_verify_Ep8xaWQJAI.html
@@ -0,0 +1 @@
+Ep8xaWQJAI
\ No newline at end of file
diff --git a/src/main/resources/static/baidu_verify_L6sR9GjEtg.html b/src/main/resources/static/baidu_verify_L6sR9GjEtg.html
new file mode 100644
index 0000000..7ddd7fd
--- /dev/null
+++ b/src/main/resources/static/baidu_verify_L6sR9GjEtg.html
@@ -0,0 +1 @@
+L6sR9GjEtg
\ No newline at end of file
diff --git a/src/main/resources/static/book_content.html b/src/main/resources/static/book_content.html
new file mode 100644
index 0000000..d6d9d48
--- /dev/null
+++ b/src/main/resources/static/book_content.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+ 帝霸
+
+
+
+
+
+
+
+
+
+
+
开灯
+
护眼
+ 字体:
大
+
中
+
小
+
+
+
+
+
+ 『章节错误,点此举报』
+ 很快,所有人都离开了小圣山,只有独孤岚留下。
当众人都离开之后,独孤岚起身,行至溪边,向李七夜鞠身大拜,说道:“云泥学院弟子,拜见少爷。”
独孤岚行大礼,李七夜缓缓张开眼睛,看了她一眼,点了点头。
“有事吗?”李七夜也仅仅是看了独孤岚一眼,依然持钓杆,神态自若,似乎没有什么比钓鱼更吸引他一样。
那怕独孤岚这样的绝世美女,李七夜那也仅仅是看了一眼而已。
独孤岚也是十分好奇,难道李七夜真的是在钓鱼吗?这都让她不由有点出神,但,她很快就收回了心思,她轻轻地向李七夜说道:“弟子只怕不是正一少师的对手。”
独孤岚也没有转弯抹角,而是直接说出了自己心中的疑惑。
李七夜不由笑了一下,轻轻地摇头,说道:“不是只怕,你的的确确不是他的对手。你与他一战,必败。”
李七夜这样的断言,独孤岚也不由沉默了一下,没有生气,也没有发怒。
换作是其他人,或者有些不悦,甚至是怒火上冲,毕竟,决战还没有开始,就已经断言独孤岚不敌正一少师了,这不是一种羞辱是什么?
独孤岚回过神来,向李七夜一鞠身,说道:“所以,弟子向少爷请教,还望少爷指点迷津。”
独孤岚的态度很诚恳,也十分的谦卑,这样的姿态,的的确确是让人喜欢,更何况她不仅仅是绝世美女,还是天姿绝世的天才。
“我没有什么好指点的。”李七夜轻轻摇了摇头,笑了笑,说道:“你对大道的领悟,已经超过了许许多多的同辈中人,你自己心里面也应该一清二楚。”
这样的赞美,独孤岚没有自傲,她沉吟了一下,最后轻轻地说道:“弟子见少爷可破解‘吞攻’,我想,少爷一定会破……”
“你猜对了。”李七夜笑着说道:“没错,我可以破正一教的‘魔吞七卷’。”
李七夜这样的话,独孤岚并没有吃惊,这是她意料之中,如果换作是别人,一定会大吃一惊,甚至对李七夜的话将信将疑。
毕竟,“魔吞七卷”那是博大精深,能破一卷,那都已经是天纵其才了,更何况是七卷呢。
说到这里,李七夜是顿了一下,看了独孤岚一眼,淡淡地说道:“就算我授你破七卷之法,你认为你就能战胜正一少师吗?”
“这个”李七夜这样的话,顿时让独孤岚不由沉吟了一下,最后她轻轻摇头,说道:“我未与正一少师交过手,不敢下断论,但,我尽全力而为。”
“心态很好。”李七夜笑了一下,淡淡地说道:“就算你修练了破解七法之术,也不见得你就是胜券在握。”
独孤岚不由沉默了一下,最后她轻轻地说道:“但,少爷一定有击败正一少师之法。”
独孤岚这样的话,李七夜没有立即回答,只是看着自己的钓杆而已,过了好一会儿之后,他这才轻轻点头,说道:“是的,击败正一少师,有何难也,千百种手段,随手拈来而已。”
李七夜这样的话是轻措淡写,若是在场有外人听了,一定会认为李七夜口出狂言,一定是会认为李七夜又在吹牛皮。
正一少师是何许人也,当今南西皇第一天才,大道无双,毫不夸张地说,在当今南西皇,举世之间,年轻一辈,只怕无人能敌也。
李七夜竟然说可以轻而易举地击败他,这只怕连正一少师自己都不会相信。
独孤岚没有置疑,她静静地听着李七夜的话,她说道:“若是少爷出手,必定是威慑八荒,正一少师败北,那也是意料中的事情。”
“好了,别给我戴高帽子。”李七夜不由笑了一下,轻轻摆手,打断了独孤岚的话。
说到这里,李七夜顿了一下,看着独孤岚,徐徐地说道:“你是想赢正一少师,还是想怎么样呢?”
独孤岚沉默了一下,然后抬头,迎上李七夜的目光,认真而坦然,说道:“对于我来说,若是能赢正一少师,那是再好不过,若是不敌,那也是情理之中的事情。我道行不如正一少师,实力有着甚大的差距,败在正一少师的手中,也未见得是什么耻辱之事。”
说到这里,独孤岚顿了一下,说道:“败在正一少师手中,只能说是愧对师门,也愧于佛陀圣地。当然,佛陀圣地屹立千百万年之久,不会因为我败于正一少师而没落,也不会因为我败于正一少师而崩溃倒塌。只能说,是我自己不够优秀,未能做到尽善尽美。”
说出这样的一席话,独孤岚神态自然,也没有任何矫情之处。
“这话说得好,说得很好。”李七夜笑了起来,为独孤岚鼓掌,这可以说是对独孤岚极高的赞美了。
独孤岚也只是笑了笑,她展颜一笑,那是美丽绝伦,不知道让多少男人是神魂颠倒,让多少男人为之一见倾魂。
李七夜也仅仅是含笑看了一眼而已。
“少爷是不是也会出手呢?”过了片刻之后,独孤岚轻轻地问道。
李七夜笑了一下,说道:“你不也是说了吗?佛陀圣地屹立千百万年之久,不会因为一败而衰落,也不会因为一败而崩分离析,佛陀圣地的底蕴依然还在,依然是藏龙卧虎,这样的一场挑战,战与不战,有什么区别呢。对于我来说,没有任何区别,也没有任何影响。”
“可是。”独孤岚忍不住说道:“以少爷的身份而言,可代表着佛陀圣地,少爷乃是佛陀圣地的……”
“不,你理解错了。”李七夜轻轻地摆手,笑着摇了摇头说道:“我从来没有代表过佛陀圣地,也没有代表过金杵王朝,那只不过是世人自作多情而已。我只是我,我也仅仅是代表着我自己而已,没有任何其他的身份。”
李七夜这样的话,让独孤岚不由呆了一下,在此之前,李七夜说出的其他任何话,独孤岚都并不为奇,但是,现在李七夜说出了这样的话,却让独孤岚不由为之吃惊了。
“少爷的意思……”独孤岚不由犹豫地看了李七夜一眼,她都不是十分肯定了。
李七夜淡淡地笑了一下,看了独孤岚一眼,意味深长,淡淡地说道:“这一战,你不能指望于我,对于这样的决战,我是没有什么兴趣。这场关乎佛陀圣地和正一教的年轻一辈之争,最后还是需要你扛起大旗,去面对这一场艰难的决战。”
独孤岚不由怔了怔,过了好一会儿,她不由深深地呼吸了一口气,不由苦笑地说道:“少爷这样的话,顿时让我感觉肩上如负千钧之重,让人窒息。”
“对于你来说,不也是一件好事?”李七夜淡淡地说道:“这正是你独挡一面的时候,也是你迈向更高峰的时刻。”独孤岚不由苦笑,说道:“但,少爷也知道,背负佛陀圣地名誉,此乃是大任也。”
天将降斯人也,必劳其心智。“李七夜悠然地说道。
既然李七夜都这样说话了,独孤岚那也没什么话可以说了。
“那,那,决战一天,少爷会来吗?”最后,独孤岚只能是这样轻轻地问道。
李七夜没有立即回答,过了片刻之后,这才看了独孤岚一下,淡淡地笑着说道:“放心吧,出不了什么大事,既然是了不起的一战,那我当然是捧场了。”
不知道为什么,李七夜这样的话,顿时让独孤岚在心里面长长地吁了一口气,李七夜没有给出任何承诺,但却让独孤岚如释重负一般。
说完这话,李七夜没有再多说什么,他闭目养神,手持钓杆,好像是睡着了一样。
独孤岚也十分好奇,为什么李七夜会一直在这里钓鱼呢,难道李七夜真的是在这里钓鱼吗?这让独孤岚充满了好奇,但,李七夜已经钓了这么久了,好像是一条鱼都没有钓到。
“少爷真的是在钓鱼吗?”过了好一会儿,独孤岚就忍不住轻轻地问道了。
但是,李七夜没有回答独孤岚的话,依然静静地坐在那里,好像真的睡着了一样。
独孤岚也没有再打扰,只是静静地站在一旁,静静地看着李七夜手持着钓杆,不过,说来也奇怪,也不知道多久过去了,李七夜的钓杆一点动静都没有,根本就没有钓到一条鱼,这都让人怀疑,李七夜会不会钓鱼呢?
也不知道过了多久,李七夜这才睁开眼睛,看了独孤岚一下,笑了一下,轻轻摇头,说道:“谁说,持杆,一定就是要钓鱼?”
独孤岚不由怔了一下,但,也觉得这话有道理,这不一定是需要钓鱼。
就在这个时候,李七夜开始收线了,一直在收,也不知道这钓线究竟有多长,一直收线都好像收不完一样,收了大半天,都没有看到钓钩。
也不知道过了多久要,李七夜终于收完了错,钓钩脱水而出。
但,当钓钩脱水而出的时候,独孤岚看得一清二楚,那根本就不是什么钓钩。
大爆料,杀死贼老天的一千种方法曝光啦!想知道怎么杀死贼老天吗?想了解这些手段都有哪些吗?来这里!!关注贼老天”即可阅览相关信息!!
+
『加入书签,方便阅读』
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/book_detail.html b/src/main/resources/static/book_detail.html
new file mode 100644
index 0000000..d63e88e
--- /dev/null
+++ b/src/main/resources/static/book_detail.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+ 帝霸
+
+
+
+
+
+
+
+
+
+
+
+
+
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
评分:9.2分
+
+
+
+
+ 开始阅读
+ 加入收藏
+
+
+ 万火儿莫名其妙的重生了,而且从堂堂的金丹修士,直接坠落尘埃,变成天赋极差的炼气期小透明。 小透明无父无母小可怜,柔弱无骨真小白花。 万火儿仰天长叹。 天道你大爷! 不过这一次不仅附赠随身空间,还另有极重承诺的天之骄子美貌未婚夫一枚。 万火儿抚胸感叹:还好,还好。 但是,除此之外,还附赠另一枚重生女! 重生女杂灵根,蓦然醒转变为天之骄女,自此之后,丹药在她手,神兽就她有。人生处处是机缘,所到处处有福缘,更有无数美男前仆后继,后宫日益壮大。 万火儿哀叹。 不同命啊~ 什么? 重生女抢她名额,找未婚夫揍她。 什么? 重生女抢她好友?让好友接着揍她。 什么? 重生女要将她未婚夫收后宫? 抱歉,绝对不行! 自此之后,柔弱小白花,踏上漫漫极品女盗之路。 信奉宗旨,只要是重生女的机缘,那就抢抢抢。只要是重生女的桃花,那就破破破。 什么?机缘本是她的?桃花也是她的? 桃花就算了,机缘绝对不放过。 敬请收看:妖孽无双女盗贼是如何装作可怜无助小白花,一路扮猪吃老虎,踏上漫漫修仙路的。
+
+
+
+
+
+
+ 最新章节
+
+ 更新: 2019-08-22 12:56:09
+
+
+
+
+
+
+
+ 查看完整目录
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/book_index.html b/src/main/resources/static/book_index.html
new file mode 100644
index 0000000..d21f887
--- /dev/null
+++ b/src/main/resources/static/book_index.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+ 帝霸
+
+
+
+
+
+
+
+
+
+
+
+↓直达页面底部
+
+
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+第345章 我在钓鱼
+第344章 我在钓鱼
+第343章 我在钓鱼
+第342章 我在钓鱼
+第341章 我在钓鱼
+第340章 我在钓鱼
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/book_search.html b/src/main/resources/static/book_search.html
new file mode 100644
index 0000000..81e5183
--- /dev/null
+++ b/src/main/resources/static/book_search.html
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+ 帝霸
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
帝霸
+
9.2分
+
作者:厌笔萧生
+
类别:玄幻奇幻
+
状态:连载
+
更新:2019-08-22
+
+
+
简介:
+
+
+ 一觉醒来,世界大变。熟悉的高中传授的是魔法,
+ 告诉大家要成为一名出色的魔法师。居住的都市之外游荡着袭击人类的魔物妖兽,
+ 虎视眈眈。崇尚科学的世界变成了崇尚魔法,偏偏有着一样以学渣看待自己的老师,
+ 一样目光异样的同学,一样社会底层挣扎的爸爸,一样纯美却不能走路的非血缘妹妹……不过,莫凡发现绝大多数人都只能够主修一系魔法,自己却是全系全能法师!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico
new file mode 100644
index 0000000..7782d23
Binary files /dev/null and b/src/main/resources/static/favicon.ico differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.001.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.001.png
new file mode 100644
index 0000000..f1aa8a5
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.001.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.002.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.002.png
new file mode 100644
index 0000000..f7ade17
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.002.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.003.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.003.png
new file mode 100644
index 0000000..3cf0cb5
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.003.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.004.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.004.png
new file mode 100644
index 0000000..6b9d22a
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.004.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.005.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.005.png
new file mode 100644
index 0000000..eab4c71
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.005.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.006.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.006.png
new file mode 100644
index 0000000..47ca516
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.006.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.007.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.007.png
new file mode 100644
index 0000000..e7c4cfe
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.007.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.008.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.008.png
new file mode 100644
index 0000000..5564cf1
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.008.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.009.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.009.png
new file mode 100644
index 0000000..c452adf
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.009.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.010.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.010.png
new file mode 100644
index 0000000..a4b26c9
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.010.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.011.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.011.png
new file mode 100644
index 0000000..71c445f
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.011.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.012.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.012.png
new file mode 100644
index 0000000..381c5fe
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.012.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.013.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.013.png
new file mode 100644
index 0000000..91b237c
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.013.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.014.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.014.png
new file mode 100644
index 0000000..646bb42
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.014.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.015.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.015.png
new file mode 100644
index 0000000..bca9ffc
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.015.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.016.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.016.png
new file mode 100644
index 0000000..eee0a1e
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.016.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.017.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.017.png
new file mode 100644
index 0000000..25856dd
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.017.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.018.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.018.png
new file mode 100644
index 0000000..7771bfb
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.018.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.019.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.019.png
new file mode 100644
index 0000000..c6947cc
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.019.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.020.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.020.png
new file mode 100644
index 0000000..58bcb5c
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.020.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.021.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.021.png
new file mode 100644
index 0000000..05bd1d2
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.021.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.022.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.022.png
new file mode 100644
index 0000000..dacaf46
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.022.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.023.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.023.png
new file mode 100644
index 0000000..badaaa1
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.023.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.024.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.024.png
new file mode 100644
index 0000000..9e10a80
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.024.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.025.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.025.png
new file mode 100644
index 0000000..2de1e28
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.025.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.026.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.026.png
new file mode 100644
index 0000000..e140735
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.026.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.027.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.027.png
new file mode 100644
index 0000000..7133a5d
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.027.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.028.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.028.png
new file mode 100644
index 0000000..799e145
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.028.png differ
diff --git a/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.030.png b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.030.png
new file mode 100644
index 0000000..6d9e86f
Binary files /dev/null and b/src/main/resources/static/html/9a4a540e-1759-4268-90fa-7fb652c3604a.030.png differ
diff --git a/src/main/resources/static/html/note_1.html b/src/main/resources/static/html/note_1.html
new file mode 100644
index 0000000..1f729f5
--- /dev/null
+++ b/src/main/resources/static/html/note_1.html
@@ -0,0 +1,270 @@
+
+
+
+
+
+ RestTemplate中文乱码问题源码分析与解决
+
+RestTemplate中文乱码问题源码分析与解决
+
+
--- 请求响应数据乱码源码原理分析
+
+
+
+
============================原理===================
+
+
//默认方式:
+
//RestTemplate restTemplate = new RestTemplate();
+
+
// 当返回的response-header的content-type属性有charset值时,
+
+
// restTemplate的 StringHttpMessageConverter会读取该charset值,并使用该值进行
+
+
//IO流 = 》字符串的转换,否则则使用默认的字符集
+
+
//
+
+
通过源码可以发现restTemplate底层默认使用了 HttpURLConnection ,可以支持其他多种http客户端,如httpclient、okhttp等,通过 工厂方法模式 创建请求:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
restTemplate调用excute方法
+
+
+
+
restTemplate调用了doExecute方法
+
+
+
+
执行请求,调用 ResponseExtractor responseExtractor.extractData()对相应结果进行数据提取
+
+
+
+
调用 HttpMessageConverterExtractor this.delegate.extractData()执行抽取数据的操作
+
+
+
+
获取response-header的content-type,
+
+
+
+
+
+
+
判断消息转换器对应的支持媒体类型supportMediaType是否包含该content-type
+
+
+
+
调用第一个包含该content-type的 GenericHttpMessageConverter转换数据读取数据
+
+
+
+
+
+
+
读取数据的时候会再一次获取 response-header的content-type 的字符集
+
如果该字符集存在,则使用该字符集进行 IO流 =》字符串 转换
+
+
+
+
+
+
+
+
+
+
案例
+
+
+
+
+
+
+
+
+
响应头中并没有content-type的header,照理说浏览器应该不知道服务端返回的输入流编码,如果和浏览器默认的编码不匹配应该会出现乱码,但是现在浏览器有编码自动识别功能,所以上面的代码没有加content-type的Header也没有问题
+
+
+
+
+
+
+
+
+
实际上下面的做法更规范:
+
+
+
源码:
+
+
+
+
+
+
+
+
+
+
+
+
+
============================原理=====================
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/html/note_2.html b/src/main/resources/static/html/note_2.html
new file mode 100644
index 0000000..af7383f
--- /dev/null
+++ b/src/main/resources/static/html/note_2.html
@@ -0,0 +1,280 @@
+
+
+
+
+
+ 服务器跨域处理
+
+跨域处理
+
+
+
跨域是什么?浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、 协议任一不同,都是跨域 。我们是采用前后端分离开发的,也是前后端分离部署的,必然会存在跨域问题。 怎么解决跨域?很简单,只需要在controller类上添加注解 @CrossOrigin 即可!这个注解其实是CORS的实现。
+
+
CORS(Cross-Origin Resource Sharing, 跨源资源共享)是W3C出的一个标准,其思 想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成 功,还是应该失败。因此,要想实现CORS进行跨域,需要服务器进行一些设置,同时前端也需要做一些配置和分析。本文简单的对服务端的配置和前端的一些设置进行分析。
+
+
+
1️⃣ 在controller类上添加注解 @CrossOrigin,表示Controller上的所以方法允许跨域,在方法上添加注解 @CrossOrigin,表示该方法允许跨域
+
+
+
@Target({ ElementType.METHOD, ElementType.TYPE })
+
+
@Retention(RetentionPolicy.RUNTIME)
+
@Documented
+
public @interface CrossOrigin {
+
+
String[] DEFAULT_ORIGINS = { "*" };
+
+
String[] DEFAULT_ALLOWED_HEADERS = { "*" };
+
+
+
boolean DEFAULT_ALLOW_CREDENTIALS = true;
+
+
+
long DEFAULT_MAX_AGE = 1800;
+
+
+
/**
+
* 同origins属性一样
+
*/
+
@AliasFor("origins")
+
String[] value() default {};
+
+
/**
+
* 所有支持域的集合,例如"http://domain1.com"。
+
* <p>这些值都显示在请求头中的Access-Control-Allow-Origin
+
+
* "*"代表所有域的请求都支持
+
* <p>如果没有定义,所有请求的域都支持
+
* @see #value
+
*/
+
@AliasFor("value")
+
String[] origins() default {};
+
+
/**
+
* 允许请求头中的header,默认都支持
+
*/
+
String[] allowedHeaders() default {};
+
+
/**
+
* 响应头中允许访问的header,默认为空
+
*/
+
String[] exposedHeaders() default {};
+
+
/**
+
* 请求支持的方法,例如"{RequestMethod.GET, RequestMethod.POST}"}。
+
+
* 默认支持RequestMapping中设置的方法
+
*/
+
RequestMethod[] methods() default {};
+
+
/**
+
* 是否允许cookie随请求发送,使用时必须指定具体的域
+
*/
+
String allowCredentials() default "";
+
+
/**
+
* 预请求的结果的有效期,默认30分钟
+
*/
+
long maxAge() default -1;
+
+
}
+
+
+
2️⃣ 配置 CorsFilter(全局配置)
+
+
@Configuration
+
+
public class GlobalCorsConfig {
+
+
@Bean
+
public CorsFilter corsFilter() {
+
//1.添加CORS配置信息
+
+
CorsConfiguration config = new CorsConfiguration();
+
//1) 允许的域,不要写*,否则cookie就无法使用了
+
+
config.addAllowedOrigin( "http://manage.shop.com" );
+
config.addAllowedOrigin( "http://www.shop.com" );
+
//2) 是否发送Cookie信息
+
+
config.setAllowCredentials( true );
+
//3) 允许的请求方式
+
+
config.addAllowedMethod( "OPTIONS" );
+
config.addAllowedMethod( "HEAD" );
+
config.addAllowedMethod( "GET" );
+
config.addAllowedMethod( "PUT" );
+
config.addAllowedMethod( "POST" );
+
config.addAllowedMethod( "DELETE" );
+
config.addAllowedMethod( "PATCH" );
+
// 4)允许的头信息
+
+
config.addAllowedHeader( "*" );
+
// 5) 有效时长
+
+
// config.setMaxAge(3600L);
+
+
+
//2.添加映射路径,我们拦截一切请求
+
+
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
+
+
configSource.registerCorsConfiguration( "/**" , config);
+
+
//3.返回新的CorsFilter.
+
+
return new CorsFilter(configSource);
+
}
+
}
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/html/note_3.html b/src/main/resources/static/html/note_3.html
new file mode 100644
index 0000000..32eb232
--- /dev/null
+++ b/src/main/resources/static/html/note_3.html
@@ -0,0 +1,243 @@
+
+
+
+
+
+ 对分布式事务的理解
+
+对分布式事务及两阶段提交和三阶段提交的理解
+
+
一、分布式数据一致性
+
+
在分布式系统中,为了保证数据的高可用,通常会将数据保留多个副本(replica),这些副本会放置在不同的物理的机器上。
+
+
1.什么是数据一致性
+
+
在数据有多份副本的情况下,如果网络、服务器或者软件出现故障,会导致部分副本写入成功,部分副本写入失败。这就造成各个副本之间的数据不一致,数据内容冲突。
+
+
造成事实上的数据不一致。
+
2.CAP定理
+
CAP理论认为在分布式的环境下设计和部署系统时,有3个核心的需求:
+
+
Consistency,Availability和Partition Tolerance,即CAP。
+
+
+
Consistency:一致性,这个和数据库ACID的一致性类似,但这里关注的所有数据节点上的数据一致性和正确性,而数据库的ACID关注的是在在一个事务内,对数据的一些约束。系统在执行过某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读取到最新值。
+
+
Availability:可用性,每一个操作总是能够在一定时间内返回结果。需要注意“一定时间”和“返回结果”。“一定时间”是指,系统结果必须在给定时间内返回。“返回结果”是指系统返回操作成功或失败的结果。
+
+
Partition Tolerance:分区容忍性,是否可以对数据进行分区。这是考虑到性能和可伸缩性。
+
+
3.数据一致性模型
+
一些分布式系统通过复制数据来提高系统的可靠性和容错性,并且将数据的不同的副本存放在不同的机器。
+
+
强一致性:
+
当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。这种是对用户最友好的,就是用户上一次写什么,下一次就保证能读到什么。根据 CAP 理论,这种实现需要牺牲可用性。
+
+
弱一致性:
+
系统并不保证续进程或者线程的访问都会返回最新的更新过的值。用户读到某一操作对系统特定数据的更新需要一段时间,我们称这段时间为“不一致性窗口”。系统在数据写入成功之后,不承诺立即可以读到最新写入的值,也不会具体的承诺多久之后可以读到。
+
+
最终一致性:
+
是弱一致性的一种特例。系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值。在没有故障发生的前提下,不一致窗口的时间主要受通信延迟,系统负载和复制副本的个数影响。DNS 是一个典型的最终一致性系统。
+
+
+
二、典型的分布式事务实例
+
+
跨行转账问题是一个典型的分布式事务,用户A向B的一个转账1000,要进行A的余额-1000,B的余额+1000,显然必须保证这两个操作的事务性。
+
+
类似的还有,电商系统中,当有用户下单后,除了在订单表插入记,还要在商品表更新库存等,特别是随着微服务架构的流行,分布式事务的场景更变得更普遍。
+
+
+
三、两阶段提交协议
+
+
两阶段提交协议是协调所有分布式原子事务参与者,并决定提交或取消(回滚)的分布式算法。
+
+
1.协议参与者
+
在两阶段提交协议中,系统一般包含两类机器(或节点):一类为协调者(coordinator),通常一个系统中只有一个;另一类为事务参与者(participants,cohorts或workers),一般包含多个,在数据存储系统中可以理解为数据副本的个数。协议中假设每个节点都会记录写前日志(write-ahead log)并持久性存储,即使节点发生故障日志也不会丢失。协议中同时假设节点不会发生永久性故障而且任意两个节点都可以互相通信。
+
+
+
+
2.两个阶段的执行
+
1.请求阶段(commit-request phase,或称表决阶段,voting phase)
+
+
在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。
+
+
在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)。
+
+
2.提交阶段(commit phase)
+
在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消。
+
+
当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。
+
+
参与者在接收到协调者发来的消息后将执行响应的操作。
+
(3)两阶段提交的缺点
+
+
1.同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。
+
+
当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
+
+
2.单点故障。由于协调者的重要性,一旦协调者发生故障。
+
参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
+
+
3.数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。
+
+
而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
+
+
(4)两阶段提交无法解决的问题
+
+
当协调者出错,同时参与者也出错时,两阶段无法保证事务执行的完整性。
+
+
考虑协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。
+
+
那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
+
+
+
四、三阶段提交协议
+
+
三阶段提交协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。
+
+
+
+
(1)三个阶段的执行
+
+
1.CanCommit阶段
+
3PC的CanCommit阶段其实和2PC的准备阶段很像。
+
+
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
+
+
2.PreCommit阶段
+
Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作。
+
+
根据响应情况,有以下两种可能。
+
A.假如Coordinator从所有的Cohort获得的反馈都是Yes响应,那么就会进行事务的预执行:
+
+
发送预提交请求。Coordinator向Cohort发送PreCommit请求,并进入Prepared阶段。
+
+
事务预提交。Cohort接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
+
+
响应反馈。如果Cohort成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
+
+
B.假如有任何一个Cohort向Coordinator发送了No响应,或者等待超时之后,Coordinator都没有接到Cohort的响应,那么就中断事务:
+
+
发送中断请求。Coordinator向所有Cohort发送abort请求。
+
+
中断事务。Cohort收到来自Coordinator的abort请求之后(或超时之后,仍未收到Cohort的请求),执行事务的中断。
+
+
3.DoCommit阶段
+
该阶段进行真正的事务提交,也可以分为以下两种情况:
+
执行提交
+
A.发送提交请求。Coordinator接收到Cohort发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有Cohort发送doCommit请求。
+
+
B.事务提交。Cohort接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
+
+
C.响应反馈。事务提交完之后,向Coordinator发送ACK响应。
+
+
D.完成事务。Coordinator接收到所有Cohort的ACK响应之后,完成事务。
+
+
中断事务
+
Coordinator没有接收到Cohort发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
+
+
(2)三阶段提交协议和两阶段提交协议的不同
+
+
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。
+
+
在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。
+
+
PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。
+
+
(2)三阶段提交协议的缺点
+
+
如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作,
+
+
而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性。
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/html/note_4.html b/src/main/resources/static/html/note_4.html
new file mode 100644
index 0000000..82e2955
--- /dev/null
+++ b/src/main/resources/static/html/note_4.html
@@ -0,0 +1,2019 @@
+
+
+
+
+
+ SpringCloud使用问题汇总
+
+SpringCloud使用问题汇总:
+
+
1.当feign调用复杂的服务接口时,报错
+
@PostMapping("/jobPosition/listJobPositionByPage")
+
+
List<MiniJobPositionVO> listJobPositionByPage(@RequestParam(value = "posName") String posName,@RequestParam(value = "jobTypeId") String jobTypeId, @RequestBody PageBean pageBean);
+
+
当调用该接口时,posName或jobTypeId传递为null时报错400 bad request,提示需要string parameter
+
+
解决方案:给参数设置required = false
+
+
+
2.集成zipkin时配置正确,zipkin-server却收不到调用信息
+
通过HTTP使用基于Zipkin的Sleuth时,如果框架集成了rabbitmq,默认会按rabbitmq的异步方式发送调用链信息,默认的以http同步方式发送调用链信息就不会生效,注释rabbitmq配置后,发送成功。
+
+
+
3.rabbitmq的异步方式发送调用链信息
+
①加入maven依赖
+
+
+
②配置rabbitmq连接信息
+
+
+
③rabbitmq控制台创建zipkin队列
+
+
+
④启动zipkin-server
+
java -jar D:\software\zipkin-server-2.10.1-exec.jar --zipkin.collector.rabbitmq.addresses=192.168.99.100:5673 --zipkin.collector.rabbitmq.username=guest --zipkin.collector.rabbitmq.password=test --zipkin.collector.rabbitmq.useSsl=false --zipkin.collector.rabbitmq.virtual-host=/ --zipkin.collector.rabbitmq.queue=zipkin
+
+
+
+
+
+
⑤docker 方式启动
+
docker run -d -p 9411:9411 --env RABBIT_ADDRESSES=192.168.99.100:5673 --env RABBIT_USER=guest --env RABBIT_P
+
+
ASSWORD=test --env RABBIT_USE_SSL=false --env RABBIT_VIRTUAL_HOST=/ --env RABBIT_QUEUE=zipkin openzipkin/zipkin
+
+
+
⑥zipkin所有属性
+
+
+
+ zipkin :
+
+
+
+
+
+
+
+ self-tracing :
+
+
+
+
+
+ # Set to true to enable self-tracing.
+
+
+
+
+
+
+ enabled : ${SELF_TRACING_ENABLED:false}
+
+
+
+
+
+
+ # percentage to self-traces to retain
+
+
+
+
+
+
+ sample-rate : ${SELF_TRACING_SAMPLE_RATE:1.0}
+
+
+
+
+
+
+ # Timeout in seconds to flush self-tracing data to storage.
+
+
+
+
+
+
+ message-timeout : ${SELF_TRACING_FLUSH_INTERVAL:1}
+
+
+
+
+
+
+ collector :
+
+
+
+
+
+ # percentage to traces to retain
+
+
+
+
+
+
+ sample-rate : ${COLLECTOR_SAMPLE_RATE:1.0}
+
+
+
+
+
+
+ http :
+
+
+
+
+
+ # Set to false to disable creation of spans via HTTP collector API
+
+
+
+
+
+
+ enabled : ${HTTP_COLLECTOR_ENABLED:true}
+
+
+
+
+
+
+ kafka :
+
+
+
+
+
+ # Kafka bootstrap broker list, comma-separated host:port values. Setting this activates the
+
+
+
+
+
+
+ # Kafka 0.10+ collector.
+
+
+
+
+
+
+ bootstrap-servers : ${KAFKA_BOOTSTRAP_SERVERS:}
+
+
+
+
+
+
+ # Name of topic to poll for spans
+
+
+
+
+
+
+ topic : ${KAFKA_TOPIC:zipkin}
+
+
+
+
+
+
+ # Consumer group this process is consuming on behalf of.
+
+
+
+
+
+
+ group-id : ${KAFKA_GROUP_ID:zipkin}
+
+
+
+
+
+
+ # Count of consumer threads consuming the topic
+
+
+
+
+
+
+ streams : ${KAFKA_STREAMS:1}
+
+
+
+
+
+
+ rabbitmq :
+
+
+
+
+
+ # RabbitMQ server address list (comma-separated list of host:port)
+
+
+
+
+
+
+ addresses : ${RABBIT_ADDRESSES:}
+
+
+
+
+
+
+ concurrency : ${RABBIT_CONCURRENCY:1}
+
+
+
+
+
+
+ # TCP connection timeout in milliseconds
+
+
+
+
+
+
+ connection-timeout : ${RABBIT_CONNECTION_TIMEOUT:60000}
+
+
+
+
+
+
+ password : ${RABBIT_PASSWORD:guest}
+
+
+
+
+
+
+ queue : ${RABBIT_QUEUE:zipkin}
+
+
+
+
+
+
+ username : ${RABBIT_USER:guest}
+
+
+
+
+
+
+ virtual-host : ${RABBIT_VIRTUAL_HOST:/}
+
+
+
+
+
+
+ useSsl : ${RABBIT_USE_SSL:false}
+
+
+
+
+
+
+ uri : ${RABBIT_URI:}
+
+
+
+
+
+
+ query :
+
+
+
+
+
+ enabled : ${QUERY_ENABLED:true}
+
+
+
+
+
+
+ # 1 day in millis
+
+
+
+
+
+
+ lookback : ${QUERY_LOOKBACK:86400000}
+
+
+
+
+
+
+ # The Cache-Control max-age (seconds) for /api/v2/services and /api/v2/spans
+
+
+
+
+
+
+ names-max-age : 300
+
+
+
+
+
+ # CORS allowed-origins.
+
+
+
+
+
+
+ allowed-origins : "*"
+
+
+
+
+
+
+
+
+
+
+
+ storage :
+
+
+
+
+
+ strict-trace-id : ${STRICT_TRACE_ID:true}
+
+
+
+
+
+
+ search-enabled : ${SEARCH_ENABLED:true}
+
+
+
+
+
+
+ type : ${STORAGE_TYPE:mem}
+
+
+
+
+
+
+ mem :
+
+
+
+
+
+ # Maximum number of spans to keep in memory. When exceeded, oldest traces (and their spans) will be purged.
+
+
+
+
+
+
+ # A safe estimate is 1K of memory per span (each span with 2 annotations + 1 binary annotation), plus
+
+
+
+
+
+
+ # 100 MB for a safety buffer. You'll need to verify in your own environment.
+
+
+
+
+
+
+ # Experimentally, it works with: max-spans of 500000 with JRE argument -Xmx600m.
+
+
+
+
+
+
+ max-spans : 500000
+
+
+
+
+
+ cassandra :
+
+
+
+
+
+ # Comma separated list of host addresses part of Cassandra cluster. Ports default to 9042 but you can also specify a custom port with 'host:port'.
+
+
+
+
+
+
+ contact-points : ${CASSANDRA_CONTACT_POINTS:localhost}
+
+
+
+
+
+
+ # Name of the datacenter that will be considered "local" for latency load balancing. When unset, load-balancing is round-robin.
+
+
+
+
+
+
+ local-dc : ${CASSANDRA_LOCAL_DC:}
+
+
+
+
+
+
+ # Will throw an exception on startup if authentication fails.
+
+
+
+
+
+
+ username : ${CASSANDRA_USERNAME:}
+
+
+
+
+
+
+ password : ${CASSANDRA_PASSWORD:}
+
+
+
+
+
+
+ keyspace : ${CASSANDRA_KEYSPACE:zipkin}
+
+
+
+
+
+
+ # Max pooled connections per datacenter-local host.
+
+
+
+
+
+
+ max-connections : ${CASSANDRA_MAX_CONNECTIONS:8}
+
+
+
+
+
+
+ # Ensuring that schema exists, if enabled tries to execute script /zipkin-cassandra-core/resources/cassandra-schema-cql3.txt.
+
+
+
+
+
+
+ ensure-schema : ${CASSANDRA_ENSURE_SCHEMA:true}
+
+
+
+
+
+
+ # 7 days in seconds
+
+
+
+
+
+
+ span-ttl : ${CASSANDRA_SPAN_TTL:604800}
+
+
+
+
+
+
+ # 3 days in seconds
+
+
+
+
+
+
+ index-ttl : ${CASSANDRA_INDEX_TTL:259200}
+
+
+
+
+
+
+ # the maximum trace index metadata entries to cache
+
+
+
+
+
+
+ index-cache-max : ${CASSANDRA_INDEX_CACHE_MAX:100000}
+
+
+
+
+
+
+ # how long to cache index metadata about a trace. 1 minute in seconds
+
+
+
+
+
+
+ index-cache-ttl : ${CASSANDRA_INDEX_CACHE_TTL:60}
+
+
+
+
+
+
+ # how many more index rows to fetch than the user-supplied query limit
+
+
+
+
+
+
+ index-fetch-multiplier : ${CASSANDRA_INDEX_FETCH_MULTIPLIER:3}
+
+
+
+
+
+
+ # Using ssl for connection, rely on Keystore
+
+
+
+
+
+
+ use-ssl : ${CASSANDRA_USE_SSL:false}
+
+
+
+
+
+
+ cassandra3 :
+
+
+
+
+
+ # Comma separated list of host addresses part of Cassandra cluster. Ports default to 9042 but you can also specify a custom port with 'host:port'.
+
+
+
+
+
+
+ contact-points : ${CASSANDRA_CONTACT_POINTS:localhost}
+
+
+
+
+
+
+ # Name of the datacenter that will be considered "local" for latency load balancing. When unset, load-balancing is round-robin.
+
+
+
+
+
+
+ local-dc : ${CASSANDRA_LOCAL_DC:}
+
+
+
+
+
+
+ # Will throw an exception on startup if authentication fails.
+
+
+
+
+
+
+ username : ${CASSANDRA_USERNAME:}
+
+
+
+
+
+
+ password : ${CASSANDRA_PASSWORD:}
+
+
+
+
+
+
+ keyspace : ${CASSANDRA_KEYSPACE:zipkin2}
+
+
+
+
+
+
+ # Max pooled connections per datacenter-local host.
+
+
+
+
+
+
+ max-connections : ${CASSANDRA_MAX_CONNECTIONS:8}
+
+
+
+
+
+
+ # Ensuring that schema exists, if enabled tries to execute script /zipkin2-schema.cql
+
+
+
+
+
+
+ ensure-schema : ${CASSANDRA_ENSURE_SCHEMA:true}
+
+
+
+
+
+
+ # how many more index rows to fetch than the user-supplied query limit
+
+
+
+
+
+
+ index-fetch-multiplier : ${CASSANDRA_INDEX_FETCH_MULTIPLIER:3}
+
+
+
+
+
+
+ # Using ssl for connection, rely on Keystore
+
+
+
+
+
+
+ use-ssl : ${CASSANDRA_USE_SSL:false}
+
+
+
+
+
+
+ elasticsearch :
+
+
+
+
+
+ # host is left unset intentionally, to defer the decision
+
+
+
+
+
+
+ hosts : ${ES_HOSTS:}
+
+
+
+
+
+
+ pipeline : ${ES_PIPELINE:}
+
+
+
+
+
+
+ max-requests : ${ES_MAX_REQUESTS:64}
+
+
+
+
+
+
+ timeout : ${ES_TIMEOUT:10000}
+
+
+
+
+
+
+ index : ${ES_INDEX:zipkin}
+
+
+
+
+
+
+ date-separator : ${ES_DATE_SEPARATOR:-}
+
+
+
+
+
+
+ index-shards : ${ES_INDEX_SHARDS:5}
+
+
+
+
+
+
+ index-replicas : ${ES_INDEX_REPLICAS:1}
+
+
+
+
+
+
+ username : ${ES_USERNAME:}
+
+
+
+
+
+
+ password : ${ES_PASSWORD:}
+
+
+
+
+
+
+ http-logging : ${ES_HTTP_LOGGING:}
+
+
+
+
+
+
+ legacy-reads-enabled : ${ES_LEGACY_READS_ENABLED:true}
+
+
+
+
+
+
+ mysql :
+
+
+
+
+
+ host : ${MYSQL_HOST:localhost}
+
+
+
+
+
+
+ port : ${MYSQL_TCP_PORT:3306}
+
+
+
+
+
+
+ username : ${MYSQL_USER:}
+
+
+
+
+
+
+ password : ${MYSQL_PASS:}
+
+
+
+
+
+
+ db : ${MYSQL_DB:zipkin}
+
+
+
+
+
+
+ max-active : ${MYSQL_MAX_CONNECTIONS:10}
+
+
+
+
+
+
+ use-ssl : ${MYSQL_USE_SSL:false}
+
+
+
+
+
+
+ ui :
+
+
+
+
+
+ enabled : ${QUERY_ENABLED:true}
+
+
+
+
+
+
+ ## Values below here are mapped to ZipkinUiProperties, served as /config.json
+
+
+
+
+
+
+ # Default limit for Find Traces
+
+
+
+
+
+
+ query-limit : 10
+
+
+
+
+
+ # The value here becomes a label in the top-right corner
+
+
+
+
+
+
+ environment :
+
+
+
+
+
+ # Default duration to look back when finding traces.
+
+
+
+
+
+
+ # Affects the "Start time" element in the UI. 1 hour in millis
+
+
+
+
+
+
+ default-lookback : 3600000
+
+
+
+
+
+ # When false, disables the "find a trace" screen
+
+
+
+
+
+
+ search-enabled : ${SEARCH_ENABLED:true}
+
+
+
+
+
+
+ # Which sites this Zipkin UI covers. Regex syntax. (e.g. http:\/\/example.com\/.*)
+
+
+
+
+
+
+ # Multiple sites can be specified, e.g.
+
+
+
+
+
+
+ # - .*example1.com
+
+
+
+
+
+
+ # - .*example2.com
+
+
+
+
+
+
+ # Default is "match all websites"
+
+
+
+
+
+
+ instrumented : .*
+
+
+
+
+
+ # URL placed into the <base> tag in the HTML
+
+
+
+
+
+
+ base-path : /zipkin
+
+
+
+
+
+
+
+
+
+
+
+ server :
+
+
+
+
+
+ port : ${QUERY_PORT:9411}
+
+
+
+
+
+
+ use-forward-headers : true
+
+
+
+
+
+ compression :
+
+
+
+
+
+ enabled : true
+
+
+
+
+
+ # compresses any response over min-response-size (default is 2KiB)
+
+
+
+
+
+
+ # Includes dynamic json content and large static assets from zipkin-ui
+
+
+
+
+
+
+ mime-types : application/json,application/javascript,text/css,image/svg
+
+
+
+
+
+
+
+
+
+
+
+
+ spring :
+
+
+
+
+
+ jmx :
+
+
+
+
+
+ # reduce startup time by excluding unexposed JMX service
+
+
+
+
+
+
+ enabled : false
+
+
+
+
+
+ mvc :
+
+
+
+
+
+ favicon :
+
+
+
+
+
+ # zipkin has its own favicon
+
+
+
+
+
+
+ enabled : false
+
+
+
+
+
+ autoconfigure :
+
+
+
+
+
+ exclude :
+
+
+
+
+
+ # otherwise we might initialize even when not needed (ex when storage type is cassandra)
+
+
+
+
+
+
+ - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+
+
+
+
+
+
+ info :
+
+
+
+
+
+ zipkin :
+
+
+
+
+
+ version : "@project.version@"
+
+
+
+
+
+
+
+
+
+
+
+
+ logging :
+
+
+
+
+
+ pattern :
+
+
+
+
+
+ level : "%clr(%5p) %clr([%X{traceId}/%X{spanId}]){yellow}"
+
+
+
+
+
+
+ level :
+
+
+
+
+
+ # Silence Invalid method name: '__can__finagle__trace__v3__'
+
+
+
+
+
+
+ com.facebook.swift.service.ThriftServiceProcessor : 'OFF'
+
+
+
+
+
+ # # investigate /api/v2/dependencies
+
+
+
+
+
+
+ # zipkin2.internal.DependencyLinker: 'DEBUG'
+
+
+
+
+
+
+ # # log cassandra queries (DEBUG is without values)
+
+
+
+
+
+
+ # com.datastax.driver.core.QueryLogger: 'TRACE'
+
+
+
+
+
+
+ # # log cassandra trace propagation
+
+
+
+
+
+
+ # com.datastax.driver.core.Message: 'TRACE'
+
+
+
+
+
+
+ # # log reason behind http collector dropped messages
+
+
+
+
+
+
+ # zipkin2.server.ZipkinHttpCollector: 'DEBUG'
+
+
+
+
+
+
+ # zipkin2.collector.kafka.KafkaCollector: 'DEBUG'
+
+
+
+
+
+
+ # zipkin2.collector.kafka08.KafkaCollector: 'DEBUG'
+
+
+
+
+
+
+ # zipkin2.collector.rabbitmq.RabbitMQCollector: 'DEBUG'
+
+
+
+
+
+
+ # zipkin2.collector.scribe.ScribeCollector: 'DEBUG'
+
+
+
+
+
+
+
+
+
+
+
+
+ management :
+
+
+
+
+
+ endpoints :
+
+
+
+
+
+ web :
+
+
+
+
+
+ exposure :
+
+
+
+
+
+ include : '*'
+
+
+
+
+
+ endpoint :
+
+
+
+
+
+ health :
+
+
+
+
+
+ show-details : always
+
+
+
+
+
+ # Disabling auto time http requests since it is added in Undertow HttpHandler in Zipkin autoconfigure
+
+
+
+
+
+
+ # Prometheus module. In Zipkin we use different naming for the http requests duration
+
+
+
+
+
+
+ metrics :
+
+
+
+
+
+ web :
+
+
+
+
+
+ server :
+
+
+
+
+
+ auto-time-requests : false
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html
new file mode 100644
index 0000000..e78ef2d
--- /dev/null
+++ b/src/main/resources/static/index.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+ 首页
+
+
+
+
+
+
+
+
+
+
+
+
+
热门小说推荐
+
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
作者:唐家三少
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
1.我真的要飞天了 - 柳一条
+
+
08-22 19:13
+
+
+ 这里没有魔法,没有斗气,没有武术,却有武魂。唐门创立万年之后的斗罗大陆上,唐门式微。一代天骄横空出世,新一代史莱克七怪能否重振唐门,谱写一曲绝世唐门之歌?
+ 百万年魂兽,手握日月摘星辰的死灵圣法神,导致唐门衰落的全新魂导器体系。一切的神奇都将一一展现。 唐门暗器能否重振雄风,唐门能否重现辉煌,一切尽在绝世唐门!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/js/common.js b/src/main/resources/static/js/common.js
new file mode 100644
index 0000000..46be523
--- /dev/null
+++ b/src/main/resources/static/js/common.js
@@ -0,0 +1,34 @@
+var token = localStorage.getItem("token");
+if (token) {
+ $.get("/user/isLogin", { "token": token}, function (data) {
+ if(data.code != 1){//未登录
+ localStorage.removeItem("token");
+ }})
+ }
+ Array.prototype.indexOf = function (val) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] == val) return i;
+ }
+ return -1;
+ };
+
+ Array.prototype.remove = function (val) {
+ var index = this.indexOf(val);
+ if (index > -1) {
+ this.splice(index, 1);
+ }
+ };
+
+
+ function readHistory() {
+
+ var books = localStorage.getItem("historyBooks");
+ var bookIds = "-1929";
+ if (books) {
+ bookIds = JSON.parse(localStorage.getItem("historyBooks")).join(",");
+ }
+ window.location.href = "/book/search?historyBookIds=" + bookIds;
+ };
+
+
+
diff --git a/src/main/resources/static/js/jquery-1.9.1.js b/src/main/resources/static/js/jquery-1.9.1.js
new file mode 100644
index 0000000..e2c203f
--- /dev/null
+++ b/src/main/resources/static/js/jquery-1.9.1.js
@@ -0,0 +1,9597 @@
+/*!
+ * jQuery JavaScript Library v1.9.1
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-2-4
+ */
+(function( window, undefined ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+ // The deferred used on DOM ready
+ readyList,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // Support: IE<9
+ // For `typeof node.method` instead of `node.method !== undefined`
+ core_strundefined = typeof undefined,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+ location = window.location,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "1.9.1",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // The ready event handler
+ completed = function( event ) {
+
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+ },
+ // Clean-up method for dom ready events
+ detach = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return String( obj );
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+ return jQuery.merge( [], parsed.childNodes );
+ },
+
+ parseJSON: function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ if ( data === null ) {
+ return data;
+ }
+
+ if ( typeof data === "string" ) {
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+ }
+ }
+ }
+
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ core_push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return core_concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( list && ( !fired || stack ) ) {
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function() {
+
+ var support, all, a,
+ input, select, fragment,
+ opt, eventName, isSupported, i,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " a ";
+
+ // Support tests won't run in some limited or non-browser environments
+ all = div.getElementsByTagName("*");
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !all || !a || !all.length ) {
+ return {};
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+ support = {
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: div.firstChild.nodeType === 3,
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: a.getAttribute("href") === "/a",
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.5/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ checkOn: !!input.value,
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Tests for enctype support on a form (#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
+
+ // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+ boxModel: document.compatMode === "CSS1Compat",
+
+ // Will be defined later
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ boxSizingReliable: true,
+ pixelPosition: false
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<9
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ // Check if we can trust getAttribute("value")
+ input = document.createElement("input");
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( input );
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
+ for ( i in { submit: true, change: true, focusin: true }) {
+ div.setAttribute( eventName = "on" + i, "t" );
+
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+ }
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv, tds,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+ support.boxSizing = ( div.offsetWidth === 4 );
+ support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== core_strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.display = "block";
+ div.innerHTML = "
";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ if ( support.inlineBlockNeedsLayout ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ all = select = fragment = opt = a = input = null;
+
+ return support;
+})();
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var i, l, thisCache,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ // Do not set data on non-element because it will not be cleared (#8335).
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
+ return false;
+ }
+
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var attrs, name,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[i].name;
+
+ if ( !name.indexOf( "data-" ) ) {
+ name = jQuery.camelCase( name.slice(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ // Try to fetch any internally stored data first
+ return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
+ }
+
+ this.each(function() {
+ jQuery.data( this, key, value );
+ });
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ hooks.cur = fn;
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook,
+ rclass = /[\t\r\n]/g,
+ rreturn = /\r/g,
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i,
+ rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ getSetInput = jQuery.support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+ elem.className = jQuery.trim( cur );
+
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( cur ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.match( core_rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ // Toggle whole class name
+ } else if ( type === core_strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var ret, hooks, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val,
+ self = jQuery(this);
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attr: function( elem, name, value ) {
+ var hooks, notxml, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === core_strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ // In IE9+, Flash objects don't have .getAttribute (#12945)
+ // Support: IE9+
+ if ( typeof elem.getAttribute !== core_strundefined ) {
+ ret = elem.getAttribute( name );
+ }
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( rboolean.test( name ) ) {
+ // Set corresponding property to false for boolean attributes
+ // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
+ if ( !getSetAttribute && ruseDefault.test( name ) ) {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ } else {
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ var
+ // Use .prop to determine if this attribute is understood as boolean
+ prop = jQuery.prop( elem, name ),
+
+ // Fetch it accordingly
+ attr = typeof prop === "boolean" && elem.getAttribute( name ),
+ detail = typeof prop === "boolean" ?
+
+ getSetInput && getSetAttribute ?
+ attr != null :
+ // oldIE fabricates an empty string for missing boolean attributes
+ // and conflates checked/selected into attroperties
+ ruseDefault.test( name ) ?
+ elem[ jQuery.camelCase( "default-" + name ) ] :
+ !!attr :
+
+ // fetch an attribute node for properties not recognized as boolean
+ elem.getAttributeNode( name );
+
+ return detail && detail.value !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// fix oldIE value attroperty
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return jQuery.nodeName( elem, "input" ) ?
+
+ // Ignore the value *property* by using defaultValue
+ elem.defaultValue :
+
+ ret && ret.specified ? ret.value : undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
+ ret.value :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ return name === "value" || value === elem.getAttribute( name ) ?
+ value :
+ undefined;
+ }
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+}
+
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret == null ? undefined : ret;
+ }
+ });
+ });
+
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ event.isTrigger = true;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ }
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== document.activeElement && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === document.activeElement && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Even when returnValue equals to undefined Firefox will still show alert
+ if ( event.result !== undefined ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === core_strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var i,
+ cachedruns,
+ Expr,
+ getText,
+ isXML,
+ compile,
+ hasDuplicate,
+ outermostContext,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsXML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+ sortOrder,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ support = {},
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Array methods
+ arr = [],
+ pop = arr.pop,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ operators = "([*^$|!~]?=)",
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments quoted,
+ // then not containing pseudos/brackets,
+ // then attribute selectors/non-parenthetical expressions,
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rsibling = /[\x20\t\r\n\f]*[+~]/,
+
+ rnative = /^[^{]+\{\s*\[native code/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rescape = /'|\\/g,
+ rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
+ funescape = function( _, escaped ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ return high !== high ?
+ escaped :
+ // BMP codepoint
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Use a stripped-down slice if we can't use a native one
+try {
+ slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+ slice = function( i ) {
+ var elem,
+ results = [];
+ while ( (elem = this[i++]) ) {
+ results.push( elem );
+ }
+ return results;
+ };
+}
+
+/**
+ * For feature detection
+ * @param {Function} fn The function to test for native support
+ */
+function isNative( fn ) {
+ return rnative.test( fn + "" );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var cache,
+ keys = [];
+
+ return (cache = function( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key ] = value);
+ });
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // release memory in IE
+ div = null;
+ }
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !documentIsXML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
+ push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && !rbuggyQSA.test(selector) ) {
+ old = true;
+ nid = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results, slice.call( newContext.querySelectorAll(
+ newSelector
+ ), 0 ) );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsXML = isXML( doc );
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.tagNameNoComments = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if attributes should be retrieved by attribute nodes
+ support.attributes = assert(function( div ) {
+ div.innerHTML = " ";
+ var type = typeof div.lastChild.getAttribute("multiple");
+ // IE8 returns a string for some attributes even when not present
+ return type !== "boolean" && type !== "string";
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getByClassName = assert(function( div ) {
+ // Opera can't find a second classname (in 9.6)
+ div.innerHTML = "
";
+ if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+ return false;
+ }
+
+ // Safari 3.2 caches class attributes and doesn't catch changes
+ div.lastChild.className = "e";
+ return div.getElementsByClassName("e").length === 2;
+ });
+
+ // Check if getElementById returns elements by name
+ // Check if getElementsByName privileges form controls or returns elements by ID
+ support.getByName = assert(function( div ) {
+ // Inject content
+ div.id = expando + 0;
+ div.innerHTML = "
";
+ docElem.insertBefore( div, docElem.firstChild );
+
+ // Test
+ var pass = doc.getElementsByName &&
+ // buggy browsers will return fewer than the correct 2
+ doc.getElementsByName( expando ).length === 2 +
+ // buggy browsers will return more than the correct 0
+ doc.getElementsByName( expando + 0 ).length;
+ support.getIdNotName = !doc.getElementById( expando );
+
+ // Cleanup
+ docElem.removeChild( div );
+
+ return pass;
+ });
+
+ // IE6/7 return modified attributes
+ Expr.attrHandle = assert(function( div ) {
+ div.innerHTML = " ";
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+ div.firstChild.getAttribute("href") === "#";
+ }) ?
+ {} :
+ {
+ "href": function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ },
+ "type": function( elem ) {
+ return elem.getAttribute("type");
+ }
+ };
+
+ // ID find and filter
+ if ( support.getIdNotName ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
+ var m = context.getElementById( id );
+
+ return m ?
+ m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.tagNameNoComments ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Name
+ Expr.find["NAME"] = support.getByName && function( tag, context ) {
+ if ( typeof context.getElementsByName !== strundefined ) {
+ return context.getElementsByName( name );
+ }
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21),
+ // no need to also add to buggyMatches since matches checks buggyQSA
+ // A support test would require too much code (would include document ready)
+ rbuggyQSA = [ ":focus" ];
+
+ if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explictly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = " ";
+
+ // IE8 - Some boolean attributes are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Opera 10-12/IE8 - ^= $= *= and empty values
+ // Should not select anything
+ div.innerHTML = " ";
+ if ( div.querySelectorAll("[i^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.webkitMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ // Document order sorting
+ sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+ var compare;
+
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
+ if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
+ if ( a === doc || contains( preferredDoc, a ) ) {
+ return -1;
+ }
+ if ( b === doc || contains( preferredDoc, b ) ) {
+ return 1;
+ }
+ return 0;
+ }
+ return compare & 4 ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition ? -1 : 1;
+ } :
+ function( a, b ) {
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Parentless nodes are either documents or disconnected
+ } else if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ // Always assume the presence of duplicates if sort doesn't
+ // pass them to our comparison function (as in Google Chrome).
+ hasDuplicate = false;
+ [0, 0].sort( sortOrder );
+ support.detectDuplicates = hasDuplicate;
+
+ return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ // rbuggyQSA always contains :focus, so no need for an existence check
+ if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ var val;
+
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ if ( !documentIsXML ) {
+ name = name.toLowerCase();
+ }
+ if ( (val = Expr.attrHandle[ name ]) ) {
+ return val( elem );
+ }
+ if ( documentIsXML || support.attributes ) {
+ return elem.getAttribute( name );
+ }
+ return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
+ name :
+ val && val.specified ? val.value : null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ i = 1,
+ j = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem === results[ i - 1 ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[5] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[4] ) {
+ match[2] = match[4];
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeName ) {
+ if ( nodeName === "*" ) {
+ return function() { return true; };
+ }
+
+ nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifider
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsXML ?
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
+ elem.lang) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+ type: type,
+ matches: match
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var data, cache, outerCache,
+ dirkey = dirruns + " " + doneName;
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+ if ( (data = cache[1]) === true || data === cachedruns ) {
+ return data === true;
+ }
+ } else {
+ cache = outerCache[ dir ] = [ dirkey ];
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
+ if ( cache[1] === true ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ // A counter to specify which element is currently being matched
+ var matcherCachedRuns = 0,
+ bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = matcherCachedRuns;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++matcherCachedRuns;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector );
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ context.nodeType === 9 && !documentIsXML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
+ if ( !context ) {
+ return results;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, slice.call( seed, 0 ) );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ documentIsXML,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Easy API for creating new setFilters
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// Initialize with the default document
+setDocument();
+
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ rneedsContext = jQuery.expr.match.needsContext,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i, ret, self,
+ len = this.length;
+
+ if ( typeof selector !== "string" ) {
+ self = this;
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ ret = [];
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, this[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
+ return ret;
+ },
+
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false) );
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true) );
+ },
+
+ is: function( selector ) {
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ rneedsContext.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ ret = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+ }
+ cur = cur.parentNode;
+ }
+ }
+
+ return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( jQuery.unique(all) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( this.length > 1 && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem ) {
+ return ( elem === qualifier ) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+ });
+}
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "", " " ],
+ legend: [ 1, "", " " ],
+ area: [ 1, "", " " ],
+ param: [ 1, "", " " ],
+ thead: [ 1, "" ],
+ tr: [ 2, "" ],
+ col: [ 2, "" ],
+ td: [ 3, "" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X", "
" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, false, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, false, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1>$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function( value ) {
+ var isFunc = jQuery.isFunction( value );
+
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( !isFunc && typeof value !== "string" ) {
+ value = jQuery( value ).not( this ).detach();
+ }
+
+ return this.domManip( [ value ], true, function( elem ) {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ if ( parent ) {
+ jQuery( this ).remove();
+ parent.insertBefore( elem, next );
+ }
+ });
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+
+ // Flatten any nested arrays
+ args = core_concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, table ? self.html() : undefined );
+ }
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call(
+ table && jQuery.nodeName( this[i], "table" ) ?
+ findOrAppend( this[i], "tbody" ) :
+ this[i],
+ node,
+ i
+ );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Hope ajax is available...
+ jQuery.ajax({
+ url: node.src,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+function findOrAppend( elem, tag ) {
+ return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ var attr = elem.getAttributeNode("type");
+ elem.type = ( attr && attr.specified ) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ core_push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( manipulation_rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a , *may* have spurious
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare or
+ wrap[1] === "" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== core_strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ core_deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+var iframe, getStyles, curCSS,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+
+ if ( !values[ index ] ) {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ var len, styles,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ var bool = typeof state === "boolean";
+
+ return this.each(function() {
+ if ( bool ? state : isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return window.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var width, minWidth, maxWidth,
+ computed = _computed || getStyles( elem ),
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+ style = elem.style;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var left, rs, rsLeft,
+ computed = _computed || getStyles( elem ),
+ ret = computed ? computed[ name ] : undefined,
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+ // Use the already-created iframe if possible
+ iframe = ( iframe ||
+ jQuery("")
+ .css( "cssText", "display:block !important" )
+ ).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+ doc.write("");
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+ display = jQuery.css( elem[0], "display" );
+ elem.remove();
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function(){
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.hover = function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+};
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+ ajax_nonce = jQuery.now(),
+
+ ajax_rquery = /\?/,
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+ jQuery.fn[ type ] = function( fn ){
+ return this.on( type, fn );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 ) {
+ isSuccess = true;
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ isSuccess = true;
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ isSuccess = ajaxConvert( s, response );
+ statusText = isSuccess.state;
+ success = isSuccess.data;
+ error = isSuccess.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ }
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields;
+
+ // Fill responseXXX fields
+ for ( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+ var conv2, current, conv, tmp,
+ converters = {},
+ i = 0,
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice(),
+ prev = dataTypes[ 0 ];
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ // Convert to each sequential dataType, tolerating list modification
+ for ( ; (current = dataTypes[++i]); ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current !== "*" ) {
+
+ // Convert response if prev dataType is non-auto and differs from current
+ if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split(" ");
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.splice( i--, 0, current );
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s["throws"] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+
+ // Update prev for next iteration
+ prev = current;
+ }
+ }
+
+ return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+var xhrCallbacks, xhrSupported,
+ xhrId = 0,
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
+ // Abort all pending requests
+ var key;
+ for ( key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ };
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+xhrSupported = jQuery.ajaxSettings.xhr();
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = jQuery.support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var handle, i,
+ xhr = s.xhr();
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( err ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, responseHeaders, statusText, responses;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occurred
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ if ( !s.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+var fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [function( prop, value ) {
+ var end, unit,
+ tween = this.createTween( prop, value ),
+ parts = rfxnum.exec( value ),
+ target = tween.cur(),
+ start = +target || 0,
+ scale = 1,
+ maxIterations = 20;
+
+ if ( parts ) {
+ end = +parts[2];
+ unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" && start ) {
+ // Iteratively approximate from a nonzero starting point
+ // Prefer the current property, because this process will be trivial if it uses the same units
+ // Fallback to end or a simple constant
+ start = jQuery.css( tween.elem, prop, true ) || end || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ tween.unit = unit;
+ tween.start = start;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
+ }
+ return tween;
+ }]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+function createTweens( animation, props ) {
+ jQuery.each( props, function( prop, value ) {
+ var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( collection[ index ].call( animation, prop, value ) ) {
+
+ // we're done with this property
+ return;
+ }
+ }
+ });
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ createTweens( animation, props );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+ var value, name, index, easing, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+ /*jshint validthis:true */
+ var prop, index, length,
+ value, dataShow, toggle,
+ tween, hooks, oldfire,
+ anim = this,
+ style = elem.style,
+ orig = {},
+ handled = [],
+ hidden = elem.nodeType && isHidden( elem );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( elem, "display" ) === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !jQuery.support.shrinkWrapBlocks ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+
+ // show/hide pass
+ for ( index in props ) {
+ value = props[ index ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ index ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+ continue;
+ }
+ handled.push( index );
+ }
+ }
+
+ length = handled.length;
+ if ( length ) {
+ dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( index = 0 ; index < length ; index++ ) {
+ prop = handled[ index ];
+ tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
+ orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Remove in 2.0 - this supports IE8's panic based approach
+// to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+ doAnimation.finish = function() {
+ anim.stop( true );
+ };
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.cur && hooks.cur.finish ) {
+ hooks.cur.finish.call( this );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
+ for( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
+ }
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ if ( timer() && jQuery.timers.push( timer ) ) {
+ jQuery.fx.start();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+};
+
+jQuery.offset = {
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.documentElement;
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || document.documentElement;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// })();
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+})( window );
diff --git a/src/main/resources/static/js/read.js b/src/main/resources/static/js/read.js
new file mode 100644
index 0000000..ddbc718
--- /dev/null
+++ b/src/main/resources/static/js/read.js
@@ -0,0 +1,197 @@
+var checkbg = "#A7A7A7";
+var nr_body = document.getElementById("read");//页面body
+var huyandiv = document.getElementById("huyandiv");//护眼div
+var lightdiv = document.getElementById("lightdiv");//灯光div
+var fontfont = document.getElementById("fontfont");//字体div
+var fontbig = document.getElementById("fontbig");//大字体div
+var fontmiddle = document.getElementById("fontmiddle");//中字体div
+var fontsmall = document.getElementById("fontsmall");//小字体div
+var nr1 = document.getElementById("chaptercontent");//内容div
+//内容页用户设置
+function nr_setbg(intype){
+ var huyandiv = document.getElementById("huyandiv");
+ var light = document.getElementById("lightdiv");
+ if(intype == "huyan"){
+ if(huyandiv.className == "button huyanon"){
+ document.cookie="light=huyan;path=/";
+ set("light","huyan");
+ }
+ else{
+ document.cookie="light=no;path=/";
+ set("light","no");
+ }
+ }
+ if(intype == "light"){
+ if(light.innerHTML == "关灯"){
+ document.cookie="light=yes;path=/";
+ set("light","yes");
+ }
+ else{
+ document.cookie="light=no;path=/";
+ set("light","no");
+ }
+ }
+ if(intype == "big"){
+ document.cookie="font=big;path=/";
+ set("font","big");
+ }
+ if(intype == "middle"){
+ document.cookie="font=middle;path=/";
+ set("font","middle");
+ }
+ if(intype == "small"){
+ document.cookie="font=small;path=/";
+ set("font","small");
+ }
+}
+
+//内容页读取设置
+function getset(){
+ var strCookie=document.cookie;
+ var arrCookie=strCookie.split("; ");
+ var light;
+ var font;
+
+ for(var i=0;i
-1) {//UC
+ window.location.href = "ext:add_favorite";
+ }
+ else if (document.all) // IE
+ window.external.AddFavorite(url, title);
+ else {
+ if(isTip){
+ alert("该浏览器不支持自动收藏,请点击Ctrl+D手动收藏!");
+ }
+ }
+ }
+
+}
+
+
+
+function SetCookie(name, value) {
+ var key = '';
+ var Days = 365;
+ var exp = new Date();
+ var domain = "";
+ exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
+ if (key == null || key == "") {
+ document.cookie = name + "=" + encodeURI(value) + ";expires=" + exp.toGMTString() + ";path=/;domain=" + domain + ";";
+ }
+ else {
+ var nameValue = GetCookie(name);
+ if (nameValue == "") {
+ document.cookie = name + "=" + key + "=" + encodeURI(value) + ";expires=" + exp.toGMTString() + ";path=/;domain=" + domain + ";";
+ }
+ else {
+ var keyValue = getCookie(name, key);
+ if (keyValue != "") {
+ nameValue = nameValue.replace(key + "=" + keyValue, key + "=" + encodeURI(value));
+ document.cookie = name + "=" + nameValue + ";expires=" + exp.toGMTString() + ";path=/;domain=" + domain + ";";
+ }
+ else {
+ document.cookie = name + "=" + nameValue + "&" + key + "=" + encodeURI(value) + ";expires=" + exp.toGMTString() + ";path=/;" + domain + ";";
+ }
+ }
+ }
+}
+
+function GetCookie(name) {
+ var nameValue = "";
+ var key = "";
+ var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
+ if (arr = document.cookie.match(reg)) {
+ nameValue = decodeURI(arr[2]);
+ }
+ if (key != null && key != "") {
+ reg = new RegExp("(^| |&)" + key + "=([^(;|&|=)]*)(&|$)");
+ if (arr = nameValue.match(reg)) {
+ return decodeURI(arr[2]);
+ }
+ else return "";
+ }
+ else {
+ return nameValue;
+ }
+}
+
+
+function DelCookie(name)
+
+{
+
+ var exp = new Date();
+
+ exp.setTime(exp.getTime() - 1);
+
+ var cval=GetCookie(name);
+
+ if(cval!=null)
+
+ document.cookie= name + "="+cval+";expires="+exp.toGMTString();
+
+}
+
+
+
+
diff --git a/src/main/resources/static/layui/css/layui.css b/src/main/resources/static/layui/css/layui.css
new file mode 100644
index 0000000..af7ddb0
--- /dev/null
+++ b/src/main/resources/static/layui/css/layui.css
@@ -0,0 +1,5018 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+.layui-inline, img {
+ display: inline-block;
+ vertical-align: middle
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 400
+}
+
+.layui-edge, .layui-header, .layui-inline, .layui-main {
+ position: relative
+}
+
+.layui-elip, .layui-form-checkbox span, .layui-form-pane .layui-form-label {
+ text-overflow: ellipsis;
+ white-space: nowrap
+}
+
+.layui-btn, .layui-edge, .layui-inline, img {
+ vertical-align: middle
+}
+
+.layui-btn, .layui-disabled, .layui-icon, .layui-unselect {
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ -moz-user-select: none
+}
+
+blockquote, body, button, dd, div, dl, dt, form, h1, h2, h3, h4, h5, h6, input, li, ol, p, pre, td, textarea, th, ul {
+ margin: 0;
+ padding: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
+}
+
+a:active, a:hover {
+ outline: 0
+}
+
+img {
+ border: none
+}
+
+li {
+ list-style: none
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0
+}
+
+h4, h5, h6 {
+ font-size: 100%
+}
+
+button, input, optgroup, option, select, textarea {
+ font-family: inherit;
+ font-size: inherit;
+ font-style: inherit;
+ font-weight: inherit;
+ outline: 0
+}
+
+pre {
+ white-space: pre-wrap;
+ white-space: -moz-pre-wrap;
+ white-space: -pre-wrap;
+ white-space: -o-pre-wrap;
+ word-wrap: break-word
+}
+
+body {
+ line-height: 24px;
+ font: 14px Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial, sans-serif
+}
+
+hr {
+ height: 1px;
+ margin: 10px 0;
+ border: 0;
+ clear: both
+}
+
+a {
+ color: #333;
+ text-decoration: none
+}
+
+a:hover {
+ color: #777
+}
+
+a cite {
+ font-style: normal;
+ *cursor: pointer
+}
+
+.layui-border-box, .layui-border-box * {
+ box-sizing: border-box
+}
+
+.layui-box, .layui-box * {
+ box-sizing: content-box
+}
+
+.layui-clear {
+ clear: both;
+ *zoom: 1
+}
+
+.layui-clear:after {
+ content: '\20';
+ clear: both;
+ *zoom: 1;
+ display: block;
+ height: 0
+}
+
+.layui-inline {
+ *display: inline;
+ *zoom: 1
+}
+
+.layui-edge {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ border-width: 6px;
+ border-style: dashed;
+ border-color: transparent;
+ overflow: hidden
+}
+
+.layui-edge-top {
+ top: -4px;
+ border-bottom-color: #999;
+ border-bottom-style: solid
+}
+
+.layui-edge-right {
+ border-left-color: #999;
+ border-left-style: solid
+}
+
+.layui-edge-bottom {
+ top: 2px;
+ border-top-color: #999;
+ border-top-style: solid
+}
+
+.layui-edge-left {
+ border-right-color: #999;
+ border-right-style: solid
+}
+
+.layui-elip {
+ overflow: hidden
+}
+
+.layui-disabled, .layui-disabled:hover {
+ color: #d2d2d2 !important;
+ cursor: not-allowed !important
+}
+
+.layui-circle {
+ border-radius: 100%
+}
+
+.layui-show {
+ display: block !important
+}
+
+.layui-hide {
+ display: none !important
+}
+
+@font-face {
+ font-family: layui-icon;
+ src: url(../font/iconfont.eot?v=240);
+ src: url(../font/iconfont.eot?v=240#iefix) format('embedded-opentype'), url(../font/iconfont.svg?v=240#iconfont) format('svg'), url(../font/iconfont.woff?v=240) format('woff'), url(../font/iconfont.ttf?v=240) format('truetype')
+}
+
+.layui-icon {
+ font-family: layui-icon !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale
+}
+
+.layui-icon-reply-fill:before {
+ content: "\e611"
+}
+
+.layui-icon-set-fill:before {
+ content: "\e614"
+}
+
+.layui-icon-menu-fill:before {
+ content: "\e60f"
+}
+
+.layui-icon-search:before {
+ content: "\e615"
+}
+
+.layui-icon-share:before {
+ content: "\e641"
+}
+
+.layui-icon-set-sm:before {
+ content: "\e620"
+}
+
+.layui-icon-engine:before {
+ content: "\e628"
+}
+
+.layui-icon-close:before {
+ content: "\1006"
+}
+
+.layui-icon-close-fill:before {
+ content: "\1007"
+}
+
+.layui-icon-chart-screen:before {
+ content: "\e629"
+}
+
+.layui-icon-star:before {
+ content: "\e600"
+}
+
+.layui-icon-circle-dot:before {
+ content: "\e617"
+}
+
+.layui-icon-chat:before {
+ content: "\e606"
+}
+
+.layui-icon-release:before {
+ content: "\e609"
+}
+
+.layui-icon-list:before {
+ content: "\e60a"
+}
+
+.layui-icon-chart:before {
+ content: "\e62c"
+}
+
+.layui-icon-ok-circle:before {
+ content: "\1005"
+}
+
+.layui-icon-layim-theme:before {
+ content: "\e61b"
+}
+
+.layui-icon-table:before {
+ content: "\e62d"
+}
+
+.layui-icon-right:before {
+ content: "\e602"
+}
+
+.layui-icon-left:before {
+ content: "\e603"
+}
+
+.layui-icon-cart-simple:before {
+ content: "\e698"
+}
+
+.layui-icon-face-cry:before {
+ content: "\e69c"
+}
+
+.layui-icon-face-smile:before {
+ content: "\e6af"
+}
+
+.layui-icon-survey:before {
+ content: "\e6b2"
+}
+
+.layui-icon-tree:before {
+ content: "\e62e"
+}
+
+.layui-icon-upload-circle:before {
+ content: "\e62f"
+}
+
+.layui-icon-add-circle:before {
+ content: "\e61f"
+}
+
+.layui-icon-download-circle:before {
+ content: "\e601"
+}
+
+.layui-icon-templeate-1:before {
+ content: "\e630"
+}
+
+.layui-icon-util:before {
+ content: "\e631"
+}
+
+.layui-icon-face-surprised:before {
+ content: "\e664"
+}
+
+.layui-icon-edit:before {
+ content: "\e642"
+}
+
+.layui-icon-speaker:before {
+ content: "\e645"
+}
+
+.layui-icon-down:before {
+ content: "\e61a"
+}
+
+.layui-icon-file:before {
+ content: "\e621"
+}
+
+.layui-icon-layouts:before {
+ content: "\e632"
+}
+
+.layui-icon-rate-half:before {
+ content: "\e6c9"
+}
+
+.layui-icon-add-circle-fine:before {
+ content: "\e608"
+}
+
+.layui-icon-prev-circle:before {
+ content: "\e633"
+}
+
+.layui-icon-read:before {
+ content: "\e705"
+}
+
+.layui-icon-404:before {
+ content: "\e61c"
+}
+
+.layui-icon-carousel:before {
+ content: "\e634"
+}
+
+.layui-icon-help:before {
+ content: "\e607"
+}
+
+.layui-icon-code-circle:before {
+ content: "\e635"
+}
+
+.layui-icon-water:before {
+ content: "\e636"
+}
+
+.layui-icon-username:before {
+ content: "\e66f"
+}
+
+.layui-icon-find-fill:before {
+ content: "\e670"
+}
+
+.layui-icon-about:before {
+ content: "\e60b"
+}
+
+.layui-icon-location:before {
+ content: "\e715"
+}
+
+.layui-icon-up:before {
+ content: "\e619"
+}
+
+.layui-icon-pause:before {
+ content: "\e651"
+}
+
+.layui-icon-date:before {
+ content: "\e637"
+}
+
+.layui-icon-layim-uploadfile:before {
+ content: "\e61d"
+}
+
+.layui-icon-delete:before {
+ content: "\e640"
+}
+
+.layui-icon-play:before {
+ content: "\e652"
+}
+
+.layui-icon-top:before {
+ content: "\e604"
+}
+
+.layui-icon-friends:before {
+ content: "\e612"
+}
+
+.layui-icon-refresh-3:before {
+ content: "\e9aa"
+}
+
+.layui-icon-ok:before {
+ content: "\e605"
+}
+
+.layui-icon-layer:before {
+ content: "\e638"
+}
+
+.layui-icon-face-smile-fine:before {
+ content: "\e60c"
+}
+
+.layui-icon-dollar:before {
+ content: "\e659"
+}
+
+.layui-icon-group:before {
+ content: "\e613"
+}
+
+.layui-icon-layim-download:before {
+ content: "\e61e"
+}
+
+.layui-icon-picture-fine:before {
+ content: "\e60d"
+}
+
+.layui-icon-link:before {
+ content: "\e64c"
+}
+
+.layui-icon-diamond:before {
+ content: "\e735"
+}
+
+.layui-icon-log:before {
+ content: "\e60e"
+}
+
+.layui-icon-rate-solid:before {
+ content: "\e67a"
+}
+
+.layui-icon-fonts-del:before {
+ content: "\e64f"
+}
+
+.layui-icon-unlink:before {
+ content: "\e64d"
+}
+
+.layui-icon-fonts-clear:before {
+ content: "\e639"
+}
+
+.layui-icon-triangle-r:before {
+ content: "\e623"
+}
+
+.layui-icon-circle:before {
+ content: "\e63f"
+}
+
+.layui-icon-radio:before {
+ content: "\e643"
+}
+
+.layui-icon-align-center:before {
+ content: "\e647"
+}
+
+.layui-icon-align-right:before {
+ content: "\e648"
+}
+
+.layui-icon-align-left:before {
+ content: "\e649"
+}
+
+.layui-icon-loading-1:before {
+ content: "\e63e"
+}
+
+.layui-icon-return:before {
+ content: "\e65c"
+}
+
+.layui-icon-fonts-strong:before {
+ content: "\e62b"
+}
+
+.layui-icon-upload:before {
+ content: "\e67c"
+}
+
+.layui-icon-dialogue:before {
+ content: "\e63a"
+}
+
+.layui-icon-video:before {
+ content: "\e6ed"
+}
+
+.layui-icon-headset:before {
+ content: "\e6fc"
+}
+
+.layui-icon-cellphone-fine:before {
+ content: "\e63b"
+}
+
+.layui-icon-add-1:before {
+ content: "\e654"
+}
+
+.layui-icon-face-smile-b:before {
+ content: "\e650"
+}
+
+.layui-icon-fonts-html:before {
+ content: "\e64b"
+}
+
+.layui-icon-form:before {
+ content: "\e63c"
+}
+
+.layui-icon-cart:before {
+ content: "\e657"
+}
+
+.layui-icon-camera-fill:before {
+ content: "\e65d"
+}
+
+.layui-icon-tabs:before {
+ content: "\e62a"
+}
+
+.layui-icon-fonts-code:before {
+ content: "\e64e"
+}
+
+.layui-icon-fire:before {
+ content: "\e756"
+}
+
+.layui-icon-set:before {
+ content: "\e716"
+}
+
+.layui-icon-fonts-u:before {
+ content: "\e646"
+}
+
+.layui-icon-triangle-d:before {
+ content: "\e625"
+}
+
+.layui-icon-tips:before {
+ content: "\e702"
+}
+
+.layui-icon-picture:before {
+ content: "\e64a"
+}
+
+.layui-icon-more-vertical:before {
+ content: "\e671"
+}
+
+.layui-icon-flag:before {
+ content: "\e66c"
+}
+
+.layui-icon-loading:before {
+ content: "\e63d"
+}
+
+.layui-icon-fonts-i:before {
+ content: "\e644"
+}
+
+.layui-icon-refresh-1:before {
+ content: "\e666"
+}
+
+.layui-icon-rmb:before {
+ content: "\e65e"
+}
+
+.layui-icon-home:before {
+ content: "\e68e"
+}
+
+.layui-icon-user:before {
+ content: "\e770"
+}
+
+.layui-icon-notice:before {
+ content: "\e667"
+}
+
+.layui-icon-login-weibo:before {
+ content: "\e675"
+}
+
+.layui-icon-voice:before {
+ content: "\e688"
+}
+
+.layui-icon-upload-drag:before {
+ content: "\e681"
+}
+
+.layui-icon-login-qq:before {
+ content: "\e676"
+}
+
+.layui-icon-snowflake:before {
+ content: "\e6b1"
+}
+
+.layui-icon-file-b:before {
+ content: "\e655"
+}
+
+.layui-icon-template:before {
+ content: "\e663"
+}
+
+.layui-icon-auz:before {
+ content: "\e672"
+}
+
+.layui-icon-console:before {
+ content: "\e665"
+}
+
+.layui-icon-app:before {
+ content: "\e653"
+}
+
+.layui-icon-prev:before {
+ content: "\e65a"
+}
+
+.layui-icon-website:before {
+ content: "\e7ae"
+}
+
+.layui-icon-next:before {
+ content: "\e65b"
+}
+
+.layui-icon-component:before {
+ content: "\e857"
+}
+
+.layui-icon-more:before {
+ content: "\e65f"
+}
+
+.layui-icon-login-wechat:before {
+ content: "\e677"
+}
+
+.layui-icon-shrink-right:before {
+ content: "\e668"
+}
+
+.layui-icon-spread-left:before {
+ content: "\e66b"
+}
+
+.layui-icon-camera:before {
+ content: "\e660"
+}
+
+.layui-icon-note:before {
+ content: "\e66e"
+}
+
+.layui-icon-refresh:before {
+ content: "\e669"
+}
+
+.layui-icon-female:before {
+ content: "\e661"
+}
+
+.layui-icon-male:before {
+ content: "\e662"
+}
+
+.layui-icon-password:before {
+ content: "\e673"
+}
+
+.layui-icon-senior:before {
+ content: "\e674"
+}
+
+.layui-icon-theme:before {
+ content: "\e66a"
+}
+
+.layui-icon-tread:before {
+ content: "\e6c5"
+}
+
+.layui-icon-praise:before {
+ content: "\e6c6"
+}
+
+.layui-icon-star-fill:before {
+ content: "\e658"
+}
+
+.layui-icon-rate:before {
+ content: "\e67b"
+}
+
+.layui-icon-template-1:before {
+ content: "\e656"
+}
+
+.layui-icon-vercode:before {
+ content: "\e679"
+}
+
+.layui-icon-cellphone:before {
+ content: "\e678"
+}
+
+.layui-icon-screen-full:before {
+ content: "\e622"
+}
+
+.layui-icon-screen-restore:before {
+ content: "\e758"
+}
+
+.layui-icon-cols:before {
+ content: "\e610"
+}
+
+.layui-icon-export:before {
+ content: "\e67d"
+}
+
+.layui-icon-print:before {
+ content: "\e66d"
+}
+
+.layui-icon-slider:before {
+ content: "\e714"
+}
+
+.layui-main {
+ width: 1140px;
+ margin: 0 auto
+}
+
+.layui-header {
+ z-index: 1000;
+ height: 60px
+}
+
+.layui-header a:hover {
+ transition: all .5s;
+ -webkit-transition: all .5s
+}
+
+.layui-side {
+ position: fixed;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 999;
+ width: 200px;
+ overflow-x: hidden
+}
+
+.layui-side-scroll {
+ position: relative;
+ width: 220px;
+ height: 100%;
+ overflow-x: hidden
+}
+
+.layui-body {
+ position: absolute;
+ left: 200px;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 998;
+ width: auto;
+ overflow: hidden;
+ overflow-y: auto;
+ box-sizing: border-box
+}
+
+.layui-layout-body {
+ overflow: hidden
+}
+
+.layui-layout-admin .layui-header {
+ background-color: #23262E
+}
+
+.layui-layout-admin .layui-side {
+ top: 60px;
+ width: 200px;
+ overflow-x: hidden
+}
+
+.layui-layout-admin .layui-body {
+ top: 60px;
+ bottom: 44px
+}
+
+.layui-layout-admin .layui-main {
+ width: auto;
+ margin: 0 15px
+}
+
+.layui-layout-admin .layui-footer {
+ position: fixed;
+ left: 200px;
+ right: 0;
+ bottom: 0;
+ height: 44px;
+ line-height: 44px;
+ padding: 0 15px;
+ background-color: #eee
+}
+
+.layui-layout-admin .layui-logo {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 200px;
+ height: 100%;
+ line-height: 60px;
+ text-align: center;
+ color: #009688;
+ font-size: 16px
+}
+
+.layui-layout-admin .layui-header .layui-nav {
+ background: 0 0
+}
+
+.layui-layout-left {
+ position: absolute !important;
+ left: 200px;
+ top: 0
+}
+
+.layui-layout-right {
+ position: absolute !important;
+ right: 0;
+ top: 0
+}
+
+.layui-container {
+ position: relative;
+ margin: 0 auto;
+ padding: 0 15px;
+ box-sizing: border-box
+}
+
+.layui-fluid {
+ position: relative;
+ margin: 0 auto;
+ padding: 0 15px
+}
+
+.layui-row:after, .layui-row:before {
+ content: '';
+ display: block;
+ clear: both
+}
+
+.layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9, .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9, .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9, .layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {
+ position: relative;
+ display: block;
+ box-sizing: border-box
+}
+
+.layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {
+ float: left
+}
+
+.layui-col-xs1 {
+ width: 8.33333333%
+}
+
+.layui-col-xs2 {
+ width: 16.66666667%
+}
+
+.layui-col-xs3 {
+ width: 25%
+}
+
+.layui-col-xs4 {
+ width: 33.33333333%
+}
+
+.layui-col-xs5 {
+ width: 41.66666667%
+}
+
+.layui-col-xs6 {
+ width: 50%
+}
+
+.layui-col-xs7 {
+ width: 58.33333333%
+}
+
+.layui-col-xs8 {
+ width: 66.66666667%
+}
+
+.layui-col-xs9 {
+ width: 75%
+}
+
+.layui-col-xs10 {
+ width: 83.33333333%
+}
+
+.layui-col-xs11 {
+ width: 91.66666667%
+}
+
+.layui-col-xs12 {
+ width: 100%
+}
+
+.layui-col-xs-offset1 {
+ margin-left: 8.33333333%
+}
+
+.layui-col-xs-offset2 {
+ margin-left: 16.66666667%
+}
+
+.layui-col-xs-offset3 {
+ margin-left: 25%
+}
+
+.layui-col-xs-offset4 {
+ margin-left: 33.33333333%
+}
+
+.layui-col-xs-offset5 {
+ margin-left: 41.66666667%
+}
+
+.layui-col-xs-offset6 {
+ margin-left: 50%
+}
+
+.layui-col-xs-offset7 {
+ margin-left: 58.33333333%
+}
+
+.layui-col-xs-offset8 {
+ margin-left: 66.66666667%
+}
+
+.layui-col-xs-offset9 {
+ margin-left: 75%
+}
+
+.layui-col-xs-offset10 {
+ margin-left: 83.33333333%
+}
+
+.layui-col-xs-offset11 {
+ margin-left: 91.66666667%
+}
+
+.layui-col-xs-offset12 {
+ margin-left: 100%
+}
+
+@media screen and (max-width: 768px) {
+ .layui-hide-xs {
+ display: none !important
+ }
+
+ .layui-show-xs-block {
+ display: block !important
+ }
+
+ .layui-show-xs-inline {
+ display: inline !important
+ }
+
+ .layui-show-xs-inline-block {
+ display: inline-block !important
+ }
+}
+
+@media screen and (min-width: 768px) {
+ .layui-container {
+ width: 750px
+ }
+
+ .layui-hide-sm {
+ display: none !important
+ }
+
+ .layui-show-sm-block {
+ display: block !important
+ }
+
+ .layui-show-sm-inline {
+ display: inline !important
+ }
+
+ .layui-show-sm-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9 {
+ float: left
+ }
+
+ .layui-col-sm1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-sm2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-sm3 {
+ width: 25%
+ }
+
+ .layui-col-sm4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-sm5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-sm6 {
+ width: 50%
+ }
+
+ .layui-col-sm7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-sm8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-sm9 {
+ width: 75%
+ }
+
+ .layui-col-sm10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-sm11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-sm12 {
+ width: 100%
+ }
+
+ .layui-col-sm-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-sm-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-sm-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-sm-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-sm-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-sm-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-sm-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-sm-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-sm-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-sm-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-sm-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-sm-offset12 {
+ margin-left: 100%
+ }
+}
+
+@media screen and (min-width: 992px) {
+ .layui-container {
+ width: 970px
+ }
+
+ .layui-hide-md {
+ display: none !important
+ }
+
+ .layui-show-md-block {
+ display: block !important
+ }
+
+ .layui-show-md-inline {
+ display: inline !important
+ }
+
+ .layui-show-md-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9 {
+ float: left
+ }
+
+ .layui-col-md1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-md2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-md3 {
+ width: 25%
+ }
+
+ .layui-col-md4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-md5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-md6 {
+ width: 50%
+ }
+
+ .layui-col-md7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-md8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-md9 {
+ width: 75%
+ }
+
+ .layui-col-md10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-md11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-md12 {
+ width: 100%
+ }
+
+ .layui-col-md-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-md-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-md-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-md-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-md-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-md-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-md-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-md-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-md-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-md-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-md-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-md-offset12 {
+ margin-left: 100%
+ }
+}
+
+@media screen and (min-width: 1200px) {
+ .layui-container {
+ width: 1170px
+ }
+
+ .layui-hide-lg {
+ display: none !important
+ }
+
+ .layui-show-lg-block {
+ display: block !important
+ }
+
+ .layui-show-lg-inline {
+ display: inline !important
+ }
+
+ .layui-show-lg-inline-block {
+ display: inline-block !important
+ }
+
+ .layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9 {
+ float: left
+ }
+
+ .layui-col-lg1 {
+ width: 8.33333333%
+ }
+
+ .layui-col-lg2 {
+ width: 16.66666667%
+ }
+
+ .layui-col-lg3 {
+ width: 25%
+ }
+
+ .layui-col-lg4 {
+ width: 33.33333333%
+ }
+
+ .layui-col-lg5 {
+ width: 41.66666667%
+ }
+
+ .layui-col-lg6 {
+ width: 50%
+ }
+
+ .layui-col-lg7 {
+ width: 58.33333333%
+ }
+
+ .layui-col-lg8 {
+ width: 66.66666667%
+ }
+
+ .layui-col-lg9 {
+ width: 75%
+ }
+
+ .layui-col-lg10 {
+ width: 83.33333333%
+ }
+
+ .layui-col-lg11 {
+ width: 91.66666667%
+ }
+
+ .layui-col-lg12 {
+ width: 100%
+ }
+
+ .layui-col-lg-offset1 {
+ margin-left: 8.33333333%
+ }
+
+ .layui-col-lg-offset2 {
+ margin-left: 16.66666667%
+ }
+
+ .layui-col-lg-offset3 {
+ margin-left: 25%
+ }
+
+ .layui-col-lg-offset4 {
+ margin-left: 33.33333333%
+ }
+
+ .layui-col-lg-offset5 {
+ margin-left: 41.66666667%
+ }
+
+ .layui-col-lg-offset6 {
+ margin-left: 50%
+ }
+
+ .layui-col-lg-offset7 {
+ margin-left: 58.33333333%
+ }
+
+ .layui-col-lg-offset8 {
+ margin-left: 66.66666667%
+ }
+
+ .layui-col-lg-offset9 {
+ margin-left: 75%
+ }
+
+ .layui-col-lg-offset10 {
+ margin-left: 83.33333333%
+ }
+
+ .layui-col-lg-offset11 {
+ margin-left: 91.66666667%
+ }
+
+ .layui-col-lg-offset12 {
+ margin-left: 100%
+ }
+}
+
+.layui-col-space1 {
+ margin: -.5px
+}
+
+.layui-col-space1 > * {
+ padding: .5px
+}
+
+.layui-col-space3 {
+ margin: -1.5px
+}
+
+.layui-col-space3 > * {
+ padding: 1.5px
+}
+
+.layui-col-space5 {
+ margin: -2.5px
+}
+
+.layui-col-space5 > * {
+ padding: 2.5px
+}
+
+.layui-col-space8 {
+ margin: -3.5px
+}
+
+.layui-col-space8 > * {
+ padding: 3.5px
+}
+
+.layui-col-space10 {
+ margin: -5px
+}
+
+.layui-col-space10 > * {
+ padding: 5px
+}
+
+.layui-col-space12 {
+ margin: -6px
+}
+
+.layui-col-space12 > * {
+ padding: 6px
+}
+
+.layui-col-space15 {
+ margin: -7.5px
+}
+
+.layui-col-space15 > * {
+ padding: 7.5px
+}
+
+.layui-col-space18 {
+ margin: -9px
+}
+
+.layui-col-space18 > * {
+ padding: 9px
+}
+
+.layui-col-space20 {
+ margin: -10px
+}
+
+.layui-col-space20 > * {
+ padding: 10px
+}
+
+.layui-col-space22 {
+ margin: -11px
+}
+
+.layui-col-space22 > * {
+ padding: 11px
+}
+
+.layui-col-space25 {
+ margin: -12.5px
+}
+
+.layui-col-space25 > * {
+ padding: 12.5px
+}
+
+.layui-col-space30 {
+ margin: -15px
+}
+
+.layui-col-space30 > * {
+ padding: 15px
+}
+
+.layui-btn, .layui-input, .layui-select, .layui-textarea, .layui-upload-button {
+ outline: 0;
+ -webkit-appearance: none;
+ transition: all .3s;
+ -webkit-transition: all .3s;
+ box-sizing: border-box
+}
+
+.layui-elem-quote {
+ margin-bottom: 10px;
+ padding: 15px;
+ line-height: 22px;
+ border-left: 5px solid #009688;
+ border-radius: 0 2px 2px 0;
+ background-color: #f2f2f2
+}
+
+.layui-quote-nm {
+ border-style: solid;
+ border-width: 1px 1px 1px 5px;
+ background: 0 0
+}
+
+.layui-elem-field {
+ margin-bottom: 10px;
+ padding: 0;
+ border-width: 1px;
+ border-style: solid
+}
+
+.layui-elem-field legend {
+ margin-left: 20px;
+ padding: 0 10px;
+ font-size: 20px;
+ font-weight: 300
+}
+
+.layui-field-title {
+ margin: 10px 0 20px;
+ border-width: 1px 0 0
+}
+
+.layui-field-box {
+ padding: 10px 15px
+}
+
+.layui-field-title .layui-field-box {
+ padding: 10px 0
+}
+
+.layui-progress {
+ position: relative;
+ height: 6px;
+ border-radius: 20px;
+ background-color: #e2e2e2
+}
+
+.layui-progress-bar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 0;
+ max-width: 100%;
+ height: 6px;
+ border-radius: 20px;
+ text-align: right;
+ background-color: #5FB878;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-progress-big, .layui-progress-big .layui-progress-bar {
+ height: 18px;
+ line-height: 18px
+}
+
+.layui-progress-text {
+ position: relative;
+ top: -20px;
+ line-height: 18px;
+ font-size: 12px;
+ color: #666
+}
+
+.layui-progress-big .layui-progress-text {
+ position: static;
+ padding: 0 10px;
+ color: #fff
+}
+
+.layui-collapse {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px
+}
+
+.layui-colla-content, .layui-colla-item {
+ border-top-width: 1px;
+ border-top-style: solid
+}
+
+.layui-colla-item:first-child {
+ border-top: none
+}
+
+.layui-colla-title {
+ position: relative;
+ height: 42px;
+ line-height: 42px;
+ padding: 0 15px 0 35px;
+ color: #333;
+ background-color: #f2f2f2;
+ cursor: pointer;
+ font-size: 14px;
+ overflow: hidden
+}
+
+.layui-colla-content {
+ display: none;
+ padding: 10px 15px;
+ line-height: 22px;
+ color: #666
+}
+
+.layui-colla-icon {
+ position: absolute;
+ left: 15px;
+ top: 0;
+ font-size: 14px
+}
+
+.layui-card {
+ margin-bottom: 15px;
+ border-radius: 2px;
+ background-color: #fff;
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .05)
+}
+
+.layui-card:last-child {
+ margin-bottom: 0
+}
+
+.layui-card-header {
+ position: relative;
+ height: 42px;
+ line-height: 42px;
+ padding: 0 15px;
+ border-bottom: 1px solid #f6f6f6;
+ color: #333;
+ border-radius: 2px 2px 0 0;
+ font-size: 14px
+}
+
+.layui-bg-black, .layui-bg-blue, .layui-bg-cyan, .layui-bg-green, .layui-bg-orange, .layui-bg-red {
+ color: #fff !important
+}
+
+.layui-card-body {
+ position: relative;
+ padding: 10px 15px;
+ line-height: 24px
+}
+
+.layui-card-body[pad15] {
+ padding: 15px
+}
+
+.layui-card-body[pad20] {
+ padding: 20px
+}
+
+.layui-card-body .layui-table {
+ margin: 5px 0
+}
+
+.layui-card .layui-tab {
+ margin: 0
+}
+
+.layui-panel-window {
+ position: relative;
+ padding: 15px;
+ border-radius: 0;
+ border-top: 5px solid #E6E6E6;
+ background-color: #fff
+}
+
+.layui-auxiliar-moving {
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100%;
+ background: 0 0;
+ z-index: 9999999999
+}
+
+.layui-form-label, .layui-form-mid, .layui-form-select, .layui-input-block, .layui-input-inline, .layui-textarea {
+ position: relative
+}
+
+.layui-bg-red {
+ background-color: #FF5722 !important
+}
+
+.layui-bg-orange {
+ background-color: #FFB800 !important
+}
+
+.layui-bg-green {
+ background-color: #009688 !important
+}
+
+.layui-bg-cyan {
+ background-color: #2F4056 !important
+}
+
+.layui-bg-blue {
+ background-color: #1E9FFF !important
+}
+
+.layui-bg-black {
+ background-color: #393D49 !important
+}
+
+.layui-bg-gray {
+ background-color: #eee !important;
+ color: #666 !important
+}
+
+.layui-badge-rim, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea {
+ border-color: #e6e6e6
+}
+
+.layui-timeline-item:before, hr {
+ background-color: #e6e6e6
+}
+
+.layui-text {
+ line-height: 22px;
+ font-size: 14px;
+ color: #666
+}
+
+.layui-text h1, .layui-text h2, .layui-text h3 {
+ font-weight: 500;
+ color: #333
+}
+
+.layui-text h1 {
+ font-size: 30px
+}
+
+.layui-text h2 {
+ font-size: 24px
+}
+
+.layui-text h3 {
+ font-size: 18px
+}
+
+.layui-text a:not(.layui-btn) {
+ color: #01AAED
+}
+
+.layui-text a:not(.layui-btn):hover {
+ text-decoration: underline
+}
+
+.layui-text ul {
+ padding: 5px 0 5px 15px
+}
+
+.layui-text ul li {
+ margin-top: 5px;
+ list-style-type: disc
+}
+
+.layui-text em, .layui-word-aux {
+ color: #999 !important;
+ padding: 0 5px !important
+}
+
+.layui-btn {
+ display: inline-block;
+ height: 38px;
+ line-height: 38px;
+ padding: 0 18px;
+ background-color: #009688;
+ color: #fff;
+ white-space: nowrap;
+ text-align: center;
+ font-size: 14px;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer
+}
+
+.layui-btn:hover {
+ opacity: .8;
+ filter: alpha(opacity=80);
+ color: #fff
+}
+
+.layui-btn:active {
+ opacity: 1;
+ filter: alpha(opacity=100)
+}
+
+.layui-btn + .layui-btn {
+ margin-left: 10px
+}
+
+.layui-btn-container {
+ font-size: 0
+}
+
+.layui-btn-container .layui-btn {
+ margin-right: 10px;
+ margin-bottom: 10px
+}
+
+.layui-btn-container .layui-btn + .layui-btn {
+ margin-left: 0
+}
+
+.layui-table .layui-btn-container .layui-btn {
+ margin-bottom: 9px
+}
+
+.layui-btn-radius {
+ border-radius: 100px
+}
+
+.layui-btn .layui-icon {
+ margin-right: 3px;
+ font-size: 18px;
+ vertical-align: bottom;
+ vertical-align: middle \9
+}
+
+.layui-btn-primary {
+ border: 1px solid #C9C9C9;
+ background-color: #fff;
+ color: #555
+}
+
+.layui-btn-primary:hover {
+ border-color: #009688;
+ color: #333
+}
+
+.layui-btn-normal {
+ background-color: #1E9FFF
+}
+
+.layui-btn-warm {
+ background-color: #FFB800
+}
+
+.layui-btn-danger {
+ background-color: #FF5722
+}
+
+.layui-btn-disabled, .layui-btn-disabled:active, .layui-btn-disabled:hover {
+ border: 1px solid #e6e6e6;
+ background-color: #FBFBFB;
+ color: #C9C9C9;
+ cursor: not-allowed;
+ opacity: 1
+}
+
+.layui-btn-lg {
+ height: 44px;
+ line-height: 44px;
+ padding: 0 25px;
+ font-size: 16px
+}
+
+.layui-btn-sm {
+ height: 30px;
+ line-height: 30px;
+ padding: 0 10px;
+ font-size: 12px
+}
+
+.layui-btn-sm i {
+ font-size: 16px !important
+}
+
+.layui-btn-xs {
+ height: 22px;
+ line-height: 22px;
+ padding: 0 5px;
+ font-size: 12px
+}
+
+.layui-btn-xs i {
+ font-size: 14px !important
+}
+
+.layui-btn-group {
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 0
+}
+
+.layui-btn-group .layui-btn {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+ border-left: 1px solid rgba(255, 255, 255, .5);
+ border-radius: 0
+}
+
+.layui-btn-group .layui-btn-primary {
+ border-left: none
+}
+
+.layui-btn-group .layui-btn-primary:hover {
+ border-color: #C9C9C9;
+ color: #009688
+}
+
+.layui-btn-group .layui-btn:first-child {
+ border-left: none;
+ border-radius: 2px 0 0 2px
+}
+
+.layui-btn-group .layui-btn-primary:first-child {
+ border-left: 1px solid #c9c9c9
+}
+
+.layui-btn-group .layui-btn:last-child {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-btn-group .layui-btn + .layui-btn {
+ margin-left: 0
+}
+
+.layui-btn-group + .layui-btn-group {
+ margin-left: 10px
+}
+
+.layui-btn-fluid {
+ width: 100%
+}
+
+.layui-input, .layui-select, .layui-textarea {
+ height: 38px;
+ line-height: 1.3;
+ line-height: 38px \9;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ border-radius: 2px
+}
+
+.layui-input::-webkit-input-placeholder, .layui-select::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder {
+ line-height: 1.3
+}
+
+.layui-input, .layui-textarea {
+ display: block;
+ width: 100%;
+ padding-left: 10px
+}
+
+.layui-input:hover, .layui-textarea:hover {
+ border-color: #D2D2D2 !important
+}
+
+.layui-input:focus, .layui-textarea:focus {
+ border-color: #C9C9C9 !important
+}
+
+.layui-textarea {
+ min-height: 100px;
+ height: auto;
+ line-height: 20px;
+ padding: 6px 10px;
+ resize: vertical
+}
+
+.layui-select {
+ padding: 0 10px
+}
+
+.layui-form input[type=checkbox], .layui-form input[type=radio], .layui-form select {
+ display: none
+}
+
+.layui-form [lay-ignore] {
+ display: initial
+}
+
+.layui-form-item {
+ margin-bottom: 15px;
+ clear: both;
+ *zoom: 1
+}
+
+.layui-form-item:after {
+ content: '\20';
+ clear: both;
+ *zoom: 1;
+ display: block;
+ height: 0
+}
+
+.layui-form-label {
+ float: left;
+ display: block;
+ padding: 9px 15px;
+ width: 80px;
+ font-weight: 400;
+ line-height: 20px;
+ text-align: right
+}
+
+.layui-form-label-col {
+ display: block;
+ float: none;
+ padding: 9px 0;
+ line-height: 20px;
+ text-align: left
+}
+
+.layui-form-item .layui-inline {
+ margin-bottom: 5px;
+ margin-right: 10px
+}
+
+.layui-input-block {
+ margin-left: 110px;
+ min-height: 36px
+}
+
+.layui-input-inline {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-item .layui-input-inline {
+ float: left;
+ width: 190px;
+ margin-right: 10px
+}
+
+.layui-form-text .layui-input-inline {
+ width: auto
+}
+
+.layui-form-mid {
+ float: left;
+ display: block;
+ padding: 9px 0 !important;
+ line-height: 20px;
+ margin-right: 10px
+}
+
+.layui-form-danger + .layui-form-select .layui-input, .layui-form-danger:focus {
+ border-color: #FF5722 !important
+}
+
+.layui-form-select .layui-input {
+ padding-right: 30px;
+ cursor: pointer
+}
+
+.layui-form-select .layui-edge {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ margin-top: -3px;
+ cursor: pointer;
+ border-width: 6px;
+ border-top-color: #c2c2c2;
+ border-top-style: solid;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-form-select dl {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 42px;
+ padding: 5px 0;
+ z-index: 899;
+ min-width: 100%;
+ border: 1px solid #d2d2d2;
+ max-height: 300px;
+ overflow-y: auto;
+ background-color: #fff;
+ border-radius: 2px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
+ box-sizing: border-box
+}
+
+.layui-form-select dl dd, .layui-form-select dl dt {
+ padding: 0 10px;
+ line-height: 36px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+.layui-form-select dl dt {
+ font-size: 12px;
+ color: #999
+}
+
+.layui-form-select dl dd {
+ cursor: pointer
+}
+
+.layui-form-select dl dd:hover {
+ background-color: #f2f2f2;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-form-select .layui-select-group dd {
+ padding-left: 20px
+}
+
+.layui-form-select dl dd.layui-select-tips {
+ padding-left: 10px !important;
+ color: #999
+}
+
+.layui-form-select dl dd.layui-this {
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-form-checkbox, .layui-form-select dl dd.layui-disabled {
+ background-color: #fff
+}
+
+.layui-form-selected dl {
+ display: block
+}
+
+.layui-form-checkbox, .layui-form-checkbox *, .layui-form-switch {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-selected .layui-edge {
+ margin-top: -9px;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ margin-top: -3px \9
+}
+
+:root .layui-form-selected .layui-edge {
+ margin-top: -9px \0/ IE9
+}
+
+.layui-form-selectup dl {
+ top: auto;
+ bottom: 42px
+}
+
+.layui-select-none {
+ margin: 5px 0;
+ text-align: center;
+ color: #999
+}
+
+.layui-select-disabled .layui-disabled {
+ border-color: #eee !important
+}
+
+.layui-select-disabled .layui-edge {
+ border-top-color: #d2d2d2
+}
+
+.layui-form-checkbox {
+ position: relative;
+ height: 30px;
+ line-height: 30px;
+ margin-right: 10px;
+ padding-right: 30px;
+ cursor: pointer;
+ font-size: 0;
+ -webkit-transition: .1s linear;
+ transition: .1s linear;
+ box-sizing: border-box
+}
+
+.layui-form-checkbox span {
+ padding: 0 10px;
+ height: 100%;
+ font-size: 14px;
+ border-radius: 2px 0 0 2px;
+ background-color: #d2d2d2;
+ color: #fff;
+ overflow: hidden
+}
+
+.layui-form-checkbox:hover span {
+ background-color: #c2c2c2
+}
+
+.layui-form-checkbox i {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 30px;
+ height: 28px;
+ border: 1px solid #d2d2d2;
+ border-left: none;
+ border-radius: 0 2px 2px 0;
+ color: #fff;
+ font-size: 20px;
+ text-align: center
+}
+
+.layui-form-checkbox:hover i {
+ border-color: #c2c2c2;
+ color: #c2c2c2
+}
+
+.layui-form-checked, .layui-form-checked:hover {
+ border-color: #5FB878
+}
+
+.layui-form-checked span, .layui-form-checked:hover span {
+ background-color: #5FB878
+}
+
+.layui-form-checked i, .layui-form-checked:hover i {
+ color: #5FB878
+}
+
+.layui-form-item .layui-form-checkbox {
+ margin-top: 4px
+}
+
+.layui-form-checkbox[lay-skin=primary] {
+ height: auto !important;
+ line-height: normal !important;
+ min-width: 18px;
+ min-height: 18px;
+ border: none !important;
+ margin-right: 0;
+ padding-left: 28px;
+ padding-right: 0;
+ background: 0 0
+}
+
+.layui-form-checkbox[lay-skin=primary] span {
+ padding-left: 0;
+ padding-right: 15px;
+ line-height: 18px;
+ background: 0 0;
+ color: #666
+}
+
+.layui-form-checkbox[lay-skin=primary] i {
+ right: auto;
+ left: 0;
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ border: 1px solid #d2d2d2;
+ font-size: 12px;
+ border-radius: 2px;
+ background-color: #fff;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-checkbox[lay-skin=primary]:hover i {
+ border-color: #5FB878;
+ color: #fff
+}
+
+.layui-form-checked[lay-skin=primary] i {
+ border-color: #5FB878;
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-checkbox-disbaled[lay-skin=primary] span {
+ background: 0 0 !important;
+ color: #c2c2c2
+}
+
+.layui-checkbox-disbaled[lay-skin=primary]:hover i {
+ border-color: #d2d2d2
+}
+
+.layui-form-item .layui-form-checkbox[lay-skin=primary] {
+ margin-top: 10px
+}
+
+.layui-form-switch {
+ position: relative;
+ height: 22px;
+ line-height: 22px;
+ min-width: 35px;
+ padding: 0 5px;
+ margin-top: 8px;
+ border: 1px solid #d2d2d2;
+ border-radius: 20px;
+ cursor: pointer;
+ background-color: #fff;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-switch i {
+ position: absolute;
+ left: 5px;
+ top: 3px;
+ width: 16px;
+ height: 16px;
+ border-radius: 20px;
+ background-color: #d2d2d2;
+ -webkit-transition: .1s linear;
+ transition: .1s linear
+}
+
+.layui-form-switch em {
+ position: relative;
+ top: 0;
+ width: 25px;
+ margin-left: 21px;
+ padding: 0 !important;
+ text-align: center !important;
+ color: #999 !important;
+ font-style: normal !important;
+ font-size: 12px
+}
+
+.layui-form-onswitch {
+ border-color: #5FB878;
+ background-color: #5FB878
+}
+
+.layui-checkbox-disbaled, .layui-checkbox-disbaled i {
+ border-color: #e2e2e2 !important
+}
+
+.layui-form-onswitch i {
+ left: 100%;
+ margin-left: -21px;
+ background-color: #fff
+}
+
+.layui-form-onswitch em {
+ margin-left: 5px;
+ margin-right: 21px;
+ color: #fff !important
+}
+
+.layui-checkbox-disbaled span {
+ background-color: #e2e2e2 !important
+}
+
+.layui-checkbox-disbaled:hover i {
+ color: #fff !important
+}
+
+[lay-radio] {
+ display: none
+}
+
+.layui-form-radio, .layui-form-radio * {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-form-radio {
+ line-height: 28px;
+ margin: 6px 10px 0 0;
+ padding-right: 10px;
+ cursor: pointer;
+ font-size: 0
+}
+
+.layui-form-radio * {
+ font-size: 14px
+}
+
+.layui-form-radio > i {
+ margin-right: 8px;
+ font-size: 22px;
+ color: #c2c2c2
+}
+
+.layui-form-radio > i:hover, .layui-form-radioed > i {
+ color: #5FB878
+}
+
+.layui-radio-disbaled > i {
+ color: #e2e2e2 !important
+}
+
+.layui-form-pane .layui-form-label {
+ width: 110px;
+ padding: 8px 15px;
+ height: 38px;
+ line-height: 20px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px 0 0 2px;
+ text-align: center;
+ background-color: #FBFBFB;
+ overflow: hidden;
+ box-sizing: border-box
+}
+
+.layui-form-pane .layui-input-inline {
+ margin-left: -1px
+}
+
+.layui-form-pane .layui-input-block {
+ margin-left: 110px;
+ left: -1px
+}
+
+.layui-form-pane .layui-input {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-form-pane .layui-form-text .layui-form-label {
+ float: none;
+ width: 100%;
+ border-radius: 2px;
+ box-sizing: border-box;
+ text-align: left
+}
+
+.layui-form-pane .layui-form-text .layui-input-inline {
+ display: block;
+ margin: 0;
+ top: -1px;
+ clear: both
+}
+
+.layui-form-pane .layui-form-text .layui-input-block {
+ margin: 0;
+ left: 0;
+ top: -1px
+}
+
+.layui-form-pane .layui-form-text .layui-textarea {
+ min-height: 100px;
+ border-radius: 0 0 2px 2px
+}
+
+.layui-form-pane .layui-form-checkbox {
+ margin: 4px 0 4px 10px
+}
+
+.layui-form-pane .layui-form-radio, .layui-form-pane .layui-form-switch {
+ margin-top: 6px;
+ margin-left: 10px
+}
+
+.layui-form-pane .layui-form-item[pane] {
+ position: relative;
+ border-width: 1px;
+ border-style: solid
+}
+
+.layui-form-pane .layui-form-item[pane] .layui-form-label {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ border-width: 0 1px 0 0
+}
+
+.layui-form-pane .layui-form-item[pane] .layui-input-inline {
+ margin-left: 110px
+}
+
+@media screen and (max-width: 450px) {
+ .layui-form-item .layui-form-label {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap
+ }
+
+ .layui-form-item .layui-inline {
+ display: block;
+ margin-right: 0;
+ margin-bottom: 20px;
+ clear: both
+ }
+
+ .layui-form-item .layui-inline:after {
+ content: '\20';
+ clear: both;
+ display: block;
+ height: 0
+ }
+
+ .layui-form-item .layui-input-inline {
+ display: block;
+ float: none;
+ left: -3px;
+ width: auto;
+ margin: 0 0 10px 112px
+ }
+
+ .layui-form-item .layui-input-inline + .layui-form-mid {
+ margin-left: 110px;
+ top: -5px;
+ padding: 0
+ }
+
+ .layui-form-item .layui-form-checkbox {
+ margin-right: 5px;
+ margin-bottom: 5px
+ }
+}
+
+.layui-layedit {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px
+}
+
+.layui-layedit-tool {
+ padding: 3px 5px;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ font-size: 0
+}
+
+.layedit-tool-fixed {
+ position: fixed;
+ top: 0;
+ border-top: 1px solid #e2e2e2
+}
+
+.layui-layedit-tool .layedit-tool-mid, .layui-layedit-tool .layui-icon {
+ display: inline-block;
+ vertical-align: middle;
+ text-align: center;
+ font-size: 14px
+}
+
+.layui-layedit-tool .layui-icon {
+ position: relative;
+ width: 32px;
+ height: 30px;
+ line-height: 30px;
+ margin: 3px 5px;
+ color: #777;
+ cursor: pointer;
+ border-radius: 2px
+}
+
+.layui-layedit-tool .layui-icon:hover {
+ color: #393D49
+}
+
+.layui-layedit-tool .layui-icon:active {
+ color: #000
+}
+
+.layui-layedit-tool .layedit-tool-active {
+ background-color: #e2e2e2;
+ color: #000
+}
+
+.layui-layedit-tool .layui-disabled, .layui-layedit-tool .layui-disabled:hover {
+ color: #d2d2d2;
+ cursor: not-allowed
+}
+
+.layui-layedit-tool .layedit-tool-mid {
+ width: 1px;
+ height: 18px;
+ margin: 0 10px;
+ background-color: #d2d2d2
+}
+
+.layedit-tool-html {
+ width: 50px !important;
+ font-size: 30px !important
+}
+
+.layedit-tool-b, .layedit-tool-code, .layedit-tool-help {
+ font-size: 16px !important
+}
+
+.layedit-tool-d, .layedit-tool-face, .layedit-tool-image, .layedit-tool-unlink {
+ font-size: 18px !important
+}
+
+.layedit-tool-image input {
+ position: absolute;
+ font-size: 0;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ opacity: .01;
+ filter: Alpha(opacity=1);
+ cursor: pointer
+}
+
+.layui-layedit-iframe iframe {
+ display: block;
+ width: 100%
+}
+
+#LAY_layedit_code {
+ overflow: hidden
+}
+
+.layui-laypage {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ margin: 10px 0;
+ font-size: 0
+}
+
+.layui-laypage > a:first-child, .layui-laypage > a:first-child em {
+ border-radius: 2px 0 0 2px
+}
+
+.layui-laypage > a:last-child, .layui-laypage > a:last-child em {
+ border-radius: 0 2px 2px 0
+}
+
+.layui-laypage > :first-child {
+ margin-left: 0 !important
+}
+
+.layui-laypage > :last-child {
+ margin-right: 0 !important
+}
+
+.layui-laypage a, .layui-laypage button, .layui-laypage input, .layui-laypage select, .layui-laypage span {
+ border: 1px solid #e2e2e2
+}
+
+.layui-laypage a, .layui-laypage span {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ padding: 0 15px;
+ height: 28px;
+ line-height: 28px;
+ margin: 0 -1px 5px 0;
+ background-color: #fff;
+ color: #333;
+ font-size: 12px
+}
+
+.layui-flow-more a *, .layui-laypage input, .layui-table-view select[lay-ignore] {
+ display: inline-block
+}
+
+.layui-laypage a:hover {
+ color: #009688
+}
+
+.layui-laypage em {
+ font-style: normal
+}
+
+.layui-laypage .layui-laypage-spr {
+ color: #999;
+ font-weight: 700
+}
+
+.layui-laypage a {
+ text-decoration: none
+}
+
+.layui-laypage .layui-laypage-curr {
+ position: relative
+}
+
+.layui-laypage .layui-laypage-curr em {
+ position: relative;
+ color: #fff
+}
+
+.layui-laypage .layui-laypage-curr .layui-laypage-em {
+ position: absolute;
+ left: -1px;
+ top: -1px;
+ padding: 1px;
+ width: 100%;
+ height: 100%;
+ background-color: #009688
+}
+
+.layui-laypage-em {
+ border-radius: 2px
+}
+
+.layui-laypage-next em, .layui-laypage-prev em {
+ font-family: Sim sun;
+ font-size: 16px
+}
+
+.layui-laypage .layui-laypage-count, .layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh, .layui-laypage .layui-laypage-skip {
+ margin-left: 10px;
+ margin-right: 10px;
+ padding: 0;
+ border: none
+}
+
+.layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh {
+ vertical-align: top
+}
+
+.layui-laypage .layui-laypage-refresh i {
+ font-size: 18px;
+ cursor: pointer
+}
+
+.layui-laypage select {
+ height: 22px;
+ padding: 3px;
+ border-radius: 2px;
+ cursor: pointer
+}
+
+.layui-laypage .layui-laypage-skip {
+ height: 30px;
+ line-height: 30px;
+ color: #999
+}
+
+.layui-laypage button, .layui-laypage input {
+ height: 30px;
+ line-height: 30px;
+ border-radius: 2px;
+ vertical-align: top;
+ background-color: #fff;
+ box-sizing: border-box
+}
+
+.layui-laypage input {
+ width: 40px;
+ margin: 0 10px;
+ padding: 0 3px;
+ text-align: center
+}
+
+.layui-laypage input:focus, .layui-laypage select:focus {
+ border-color: #009688 !important
+}
+
+.layui-laypage button {
+ margin-left: 10px;
+ padding: 0 10px;
+ cursor: pointer
+}
+
+.layui-table, .layui-table-view {
+ margin: 10px 0
+}
+
+.layui-flow-more {
+ margin: 10px 0;
+ text-align: center;
+ color: #999;
+ font-size: 14px
+}
+
+.layui-flow-more a {
+ height: 32px;
+ line-height: 32px
+}
+
+.layui-flow-more a * {
+ vertical-align: top
+}
+
+.layui-flow-more a cite {
+ padding: 0 20px;
+ border-radius: 3px;
+ background-color: #eee;
+ color: #333;
+ font-style: normal
+}
+
+.layui-flow-more a cite:hover {
+ opacity: .8
+}
+
+.layui-flow-more a i {
+ font-size: 30px;
+ color: #737383
+}
+
+.layui-table {
+ width: 100%;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-table tr {
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-table th {
+ text-align: left;
+ font-weight: 400
+}
+
+.layui-table tbody tr:hover, .layui-table thead tr, .layui-table-click, .layui-table-header, .layui-table-hover, .layui-table-mend, .layui-table-patch, .layui-table-tool, .layui-table-total, .layui-table-total tr, .layui-table[lay-even] tr:nth-child(even) {
+ background-color: #f2f2f2
+}
+
+.layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view, .layui-table[lay-skin=line], .layui-table[lay-skin=row] {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #e6e6e6
+}
+
+.layui-table td, .layui-table th {
+ position: relative;
+ padding: 9px 15px;
+ min-height: 20px;
+ line-height: 20px;
+ font-size: 14px
+}
+
+.layui-table[lay-skin=line] td, .layui-table[lay-skin=line] th {
+ border-width: 0 0 1px
+}
+
+.layui-table[lay-skin=row] td, .layui-table[lay-skin=row] th {
+ border-width: 0 1px 0 0
+}
+
+.layui-table[lay-skin=nob] td, .layui-table[lay-skin=nob] th {
+ border: none
+}
+
+.layui-table img {
+ max-width: 100px
+}
+
+.layui-table[lay-size=lg] td, .layui-table[lay-size=lg] th {
+ padding: 15px 30px
+}
+
+.layui-table-view .layui-table[lay-size=lg] .layui-table-cell {
+ height: 40px;
+ line-height: 40px
+}
+
+.layui-table[lay-size=sm] td, .layui-table[lay-size=sm] th {
+ font-size: 12px;
+ padding: 5px 10px
+}
+
+.layui-table-view .layui-table[lay-size=sm] .layui-table-cell {
+ height: 20px;
+ line-height: 20px
+}
+
+.layui-table[lay-data] {
+ display: none
+}
+
+.layui-table-box {
+ position: relative;
+ overflow: hidden
+}
+
+.layui-table-view .layui-table {
+ position: relative;
+ width: auto;
+ margin: 0
+}
+
+.layui-table-view .layui-table[lay-skin=line] {
+ border-width: 0 1px 0 0
+}
+
+.layui-table-view .layui-table[lay-skin=row] {
+ border-width: 0 0 1px
+}
+
+.layui-table-view .layui-table td, .layui-table-view .layui-table th {
+ padding: 5px 0;
+ border-top: none;
+ border-left: none
+}
+
+.layui-table-view .layui-table th.layui-unselect .layui-table-cell span {
+ cursor: pointer
+}
+
+.layui-table-view .layui-table td {
+ cursor: default
+}
+
+.layui-table-view .layui-form-checkbox[lay-skin=primary] i {
+ width: 18px;
+ height: 18px
+}
+
+.layui-table-view .layui-form-radio {
+ line-height: 0;
+ padding: 0
+}
+
+.layui-table-view .layui-form-radio > i {
+ margin: 0;
+ font-size: 20px
+}
+
+.layui-table-init {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ z-index: 110
+}
+
+.layui-table-init .layui-icon {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ margin: -15px 0 0 -15px;
+ font-size: 30px;
+ color: #c2c2c2
+}
+
+.layui-table-header {
+ border-width: 0 0 1px;
+ overflow: hidden
+}
+
+.layui-table-header .layui-table {
+ margin-bottom: -1px
+}
+
+.layui-table-tool .layui-inline[lay-event] {
+ position: relative;
+ width: 26px;
+ height: 26px;
+ padding: 5px;
+ line-height: 16px;
+ margin-right: 10px;
+ text-align: center;
+ color: #333;
+ border: 1px solid #ccc;
+ cursor: pointer;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-table-tool .layui-inline[lay-event]:hover {
+ border: 1px solid #999
+}
+
+.layui-table-tool-temp {
+ padding-right: 120px
+}
+
+.layui-table-tool-self {
+ position: absolute;
+ right: 17px;
+ top: 10px
+}
+
+.layui-table-tool .layui-table-tool-self .layui-inline[lay-event] {
+ margin: 0 0 0 10px
+}
+
+.layui-table-tool-panel {
+ position: absolute;
+ top: 29px;
+ left: -1px;
+ padding: 5px 0;
+ min-width: 150px;
+ min-height: 40px;
+ border: 1px solid #d2d2d2;
+ text-align: left;
+ overflow-y: auto;
+ background-color: #fff;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12)
+}
+
+.layui-table-cell, .layui-table-tool-panel li {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap
+}
+
+.layui-table-tool-panel li {
+ padding: 0 10px;
+ line-height: 30px;
+ -webkit-transition: .5s all;
+ transition: .5s all
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] {
+ width: 100%;
+ padding-left: 28px
+}
+
+.layui-table-tool-panel li:hover {
+ background-color: #f2f2f2
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i {
+ position: absolute;
+ left: 0;
+ top: 0
+}
+
+.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span {
+ padding: 0
+}
+
+.layui-table-tool .layui-table-tool-self .layui-table-tool-panel {
+ left: auto;
+ right: -1px
+}
+
+.layui-table-col-set {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 20px;
+ height: 100%;
+ border-width: 0 0 0 1px;
+ background-color: #fff
+}
+
+.layui-table-sort {
+ width: 10px;
+ height: 20px;
+ margin-left: 5px;
+ cursor: pointer !important
+}
+
+.layui-table-sort .layui-edge {
+ position: absolute;
+ left: 5px;
+ border-width: 5px
+}
+
+.layui-table-sort .layui-table-sort-asc {
+ top: 3px;
+ border-top: none;
+ border-bottom-style: solid;
+ border-bottom-color: #b2b2b2
+}
+
+.layui-table-sort .layui-table-sort-asc:hover {
+ border-bottom-color: #666
+}
+
+.layui-table-sort .layui-table-sort-desc {
+ bottom: 5px;
+ border-bottom: none;
+ border-top-style: solid;
+ border-top-color: #b2b2b2
+}
+
+.layui-table-sort .layui-table-sort-desc:hover {
+ border-top-color: #666
+}
+
+.layui-table-sort[lay-sort=asc] .layui-table-sort-asc {
+ border-bottom-color: #000
+}
+
+.layui-table-sort[lay-sort=desc] .layui-table-sort-desc {
+ border-top-color: #000
+}
+
+.layui-table-cell {
+ height: 28px;
+ line-height: 28px;
+ padding: 0 15px;
+ position: relative;
+ box-sizing: border-box
+}
+
+.layui-table-cell .layui-form-checkbox[lay-skin=primary] {
+ top: -1px;
+ padding: 0
+}
+
+.layui-table-cell .layui-table-link {
+ color: #01AAED
+}
+
+.laytable-cell-checkbox, .laytable-cell-numbers, .laytable-cell-radio, .laytable-cell-space {
+ padding: 0;
+ text-align: center
+}
+
+.layui-table-body {
+ position: relative;
+ overflow: auto;
+ margin-right: -1px;
+ margin-bottom: -1px
+}
+
+.layui-table-body .layui-none {
+ line-height: 26px;
+ padding: 15px;
+ text-align: center;
+ color: #999
+}
+
+.layui-table-fixed {
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 101
+}
+
+.layui-table-fixed .layui-table-body {
+ overflow: hidden
+}
+
+.layui-table-fixed-l {
+ box-shadow: 0 -1px 8px rgba(0, 0, 0, .08)
+}
+
+.layui-table-fixed-r {
+ left: auto;
+ right: -1px;
+ border-width: 0 0 0 1px;
+ box-shadow: -1px 0 8px rgba(0, 0, 0, .08)
+}
+
+.layui-table-fixed-r .layui-table-header {
+ position: relative;
+ overflow: visible
+}
+
+.layui-table-mend {
+ position: absolute;
+ right: -49px;
+ top: 0;
+ height: 100%;
+ width: 50px
+}
+
+.layui-table-tool {
+ position: relative;
+ z-index: 890;
+ width: 100%;
+ min-height: 50px;
+ line-height: 30px;
+ padding: 10px 15px;
+ border-width: 0 0 1px
+}
+
+.layui-table-tool .layui-btn-container {
+ margin-bottom: -10px
+}
+
+.layui-table-page, .layui-table-total {
+ border-width: 1px 0 0;
+ margin-bottom: -1px;
+ overflow: hidden
+}
+
+.layui-table-page {
+ position: relative;
+ width: 100%;
+ padding: 7px 7px 0;
+ height: 41px;
+ font-size: 12px;
+ white-space: nowrap
+}
+
+.layui-table-page > div {
+ height: 26px
+}
+
+.layui-table-page .layui-laypage {
+ margin: 0
+}
+
+.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span {
+ height: 26px;
+ line-height: 26px;
+ margin-bottom: 10px;
+ border: none;
+ background: 0 0
+}
+
+.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span.layui-laypage-curr {
+ padding: 0 12px
+}
+
+.layui-table-page .layui-laypage span {
+ margin-left: 0;
+ padding: 0
+}
+
+.layui-table-page .layui-laypage .layui-laypage-prev {
+ margin-left: -7px !important
+}
+
+.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em {
+ left: 0;
+ top: 0;
+ padding: 0
+}
+
+.layui-table-page .layui-laypage button, .layui-table-page .layui-laypage input {
+ height: 26px;
+ line-height: 26px
+}
+
+.layui-table-page .layui-laypage input {
+ width: 40px
+}
+
+.layui-table-page .layui-laypage button {
+ padding: 0 10px
+}
+
+.layui-table-page select {
+ height: 18px
+}
+
+.layui-table-patch .layui-table-cell {
+ padding: 0;
+ width: 30px
+}
+
+.layui-table-edit {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ padding: 0 14px 1px;
+ border-radius: 0;
+ box-shadow: 1px 1px 20px rgba(0, 0, 0, .15)
+}
+
+.layui-table-edit:focus {
+ border-color: #5FB878 !important
+}
+
+select.layui-table-edit {
+ padding: 0 0 0 10px;
+ border-color: #C9C9C9
+}
+
+.layui-table-view .layui-form-checkbox, .layui-table-view .layui-form-radio, .layui-table-view .layui-form-switch {
+ top: 0;
+ margin: 0;
+ box-sizing: content-box
+}
+
+.layui-table-view .layui-form-checkbox {
+ top: -1px;
+ height: 26px;
+ line-height: 26px
+}
+
+.layui-table-view .layui-form-checkbox i {
+ height: 26px
+}
+
+.layui-table-grid .layui-table-cell {
+ overflow: visible
+}
+
+.layui-table-grid-down {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 26px;
+ height: 100%;
+ padding: 5px 0;
+ border-width: 0 0 0 1px;
+ text-align: center;
+ background-color: #fff;
+ color: #999;
+ cursor: pointer
+}
+
+.layui-table-grid-down .layui-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin: -8px 0 0 -8px
+}
+
+.layui-table-grid-down:hover {
+ background-color: #fbfbfb
+}
+
+body .layui-table-tips .layui-layer-content {
+ background: 0 0;
+ padding: 0;
+ box-shadow: 0 1px 6px rgba(0, 0, 0, .12)
+}
+
+.layui-table-tips-main {
+ margin: -44px 0 0 -1px;
+ max-height: 150px;
+ padding: 8px 15px;
+ font-size: 14px;
+ overflow-y: scroll;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-table-tips-c {
+ position: absolute;
+ right: -3px;
+ top: -13px;
+ width: 20px;
+ height: 20px;
+ padding: 3px;
+ cursor: pointer;
+ background-color: #666;
+ border-radius: 50%;
+ color: #fff
+}
+
+.layui-table-tips-c:hover {
+ background-color: #777
+}
+
+.layui-table-tips-c:before {
+ position: relative;
+ right: -2px
+}
+
+.layui-upload-file {
+ display: none !important;
+ opacity: .01;
+ filter: Alpha(opacity=1)
+}
+
+.layui-upload-drag, .layui-upload-form, .layui-upload-wrap {
+ display: inline-block
+}
+
+.layui-upload-list {
+ margin: 10px 0
+}
+
+.layui-upload-choose {
+ padding: 0 10px;
+ color: #999
+}
+
+.layui-upload-drag {
+ position: relative;
+ padding: 30px;
+ border: 1px dashed #e2e2e2;
+ background-color: #fff;
+ text-align: center;
+ cursor: pointer;
+ color: #999
+}
+
+.layui-upload-drag .layui-icon {
+ font-size: 50px;
+ color: #009688
+}
+
+.layui-upload-drag[lay-over] {
+ border-color: #009688
+}
+
+.layui-upload-iframe {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border: 0;
+ visibility: hidden
+}
+
+.layui-upload-wrap {
+ position: relative;
+ vertical-align: middle
+}
+
+.layui-upload-wrap .layui-upload-file {
+ display: block !important;
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 10;
+ font-size: 100px;
+ width: 100%;
+ height: 100%;
+ opacity: .01;
+ filter: Alpha(opacity=1);
+ cursor: pointer
+}
+
+.layui-tree {
+ line-height: 26px
+}
+
+.layui-tree li {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap
+}
+
+.layui-tree li .layui-tree-spread, .layui-tree li a {
+ display: inline-block;
+ vertical-align: top;
+ height: 26px;
+ *display: inline;
+ *zoom: 1;
+ cursor: pointer
+}
+
+.layui-tree li a {
+ font-size: 0
+}
+
+.layui-tree li a i {
+ font-size: 16px
+}
+
+.layui-tree li a cite {
+ padding: 0 6px;
+ font-size: 14px;
+ font-style: normal
+}
+
+.layui-tree li i {
+ padding-left: 6px;
+ color: #333;
+ -moz-user-select: none
+}
+
+.layui-tree li .layui-tree-check {
+ font-size: 13px
+}
+
+.layui-tree li .layui-tree-check:hover {
+ color: #009E94
+}
+
+.layui-tree li ul {
+ display: none;
+ margin-left: 20px
+}
+
+.layui-tree li .layui-tree-enter {
+ line-height: 24px;
+ border: 1px dotted #000
+}
+
+.layui-tree-drag {
+ display: none;
+ position: absolute;
+ left: -666px;
+ top: -666px;
+ background-color: #f2f2f2;
+ padding: 5px 10px;
+ border: 1px dotted #000;
+ white-space: nowrap
+}
+
+.layui-tree-drag i {
+ padding-right: 5px
+}
+
+.layui-nav {
+ position: relative;
+ padding: 0 20px;
+ background-color: #393D49;
+ color: #fff;
+ border-radius: 2px;
+ font-size: 0;
+ box-sizing: border-box
+}
+
+.layui-nav * {
+ font-size: 14px
+}
+
+.layui-nav .layui-nav-item {
+ position: relative;
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ line-height: 60px
+}
+
+.layui-nav .layui-nav-item a {
+ display: block;
+ padding: 0 20px;
+ color: #fff;
+ color: rgba(255, 255, 255, .7);
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 0;
+ height: 5px;
+ background-color: #5FB878;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-nav-bar {
+ z-index: 1000
+}
+
+.layui-nav .layui-nav-item a:hover, .layui-nav .layui-this a {
+ color: #fff
+}
+
+.layui-nav .layui-this:after {
+ content: '';
+ top: auto;
+ bottom: 0;
+ width: 100%
+}
+
+.layui-nav-img {
+ width: 30px;
+ height: 30px;
+ margin-right: 10px;
+ border-radius: 50%
+}
+
+.layui-nav .layui-nav-more {
+ content: '';
+ width: 0;
+ height: 0;
+ border-style: solid dashed dashed;
+ border-color: #fff transparent transparent;
+ overflow: hidden;
+ cursor: pointer;
+ transition: all .2s;
+ -webkit-transition: all .2s;
+ position: absolute;
+ top: 50%;
+ right: 3px;
+ margin-top: -3px;
+ border-width: 6px;
+ border-top-color: rgba(255, 255, 255, .7)
+}
+
+.layui-nav .layui-nav-mored, .layui-nav-itemed > a .layui-nav-more {
+ margin-top: -9px;
+ border-style: dashed dashed solid;
+ border-color: transparent transparent #fff
+}
+
+.layui-nav-child {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 65px;
+ min-width: 100%;
+ line-height: 36px;
+ padding: 5px 0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
+ border: 1px solid #d2d2d2;
+ background-color: #fff;
+ z-index: 100;
+ border-radius: 2px;
+ white-space: nowrap
+}
+
+.layui-nav .layui-nav-child a {
+ color: #333
+}
+
+.layui-nav .layui-nav-child a:hover {
+ background-color: #f2f2f2;
+ color: #000
+}
+
+.layui-nav-child dd {
+ position: relative
+}
+
+.layui-nav .layui-nav-child dd.layui-this a, .layui-nav-child dd.layui-this {
+ background-color: #5FB878;
+ color: #fff
+}
+
+.layui-nav-child dd.layui-this:after {
+ display: none
+}
+
+.layui-nav-tree {
+ width: 200px;
+ padding: 0
+}
+
+.layui-nav-tree .layui-nav-item {
+ display: block;
+ width: 100%;
+ line-height: 45px
+}
+
+.layui-nav-tree .layui-nav-item a {
+ position: relative;
+ height: 45px;
+ line-height: 45px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap
+}
+
+.layui-nav-tree .layui-nav-item a:hover {
+ background-color: #4E5465
+}
+
+.layui-nav-tree .layui-nav-bar {
+ width: 5px;
+ height: 0;
+ background-color: #009688
+}
+
+.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-this, .layui-nav-tree .layui-this > a, .layui-nav-tree .layui-this > a:hover {
+ background-color: #009688;
+ color: #fff
+}
+
+.layui-nav-tree .layui-this:after {
+ display: none
+}
+
+.layui-nav-itemed > a, .layui-nav-tree .layui-nav-title a, .layui-nav-tree .layui-nav-title a:hover {
+ color: #fff !important
+}
+
+.layui-nav-tree .layui-nav-child {
+ position: relative;
+ z-index: 0;
+ top: 0;
+ border: none;
+ box-shadow: none
+}
+
+.layui-nav-tree .layui-nav-child a {
+ height: 40px;
+ line-height: 40px;
+ color: #fff;
+ color: rgba(255, 255, 255, .7)
+}
+
+.layui-nav-tree .layui-nav-child, .layui-nav-tree .layui-nav-child a:hover {
+ background: 0 0;
+ color: #fff
+}
+
+.layui-nav-tree .layui-nav-more {
+ right: 10px
+}
+
+.layui-nav-itemed > .layui-nav-child {
+ display: block;
+ padding: 0;
+ background-color: rgba(0, 0, 0, .3) !important
+}
+
+.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child {
+ display: block
+}
+
+.layui-nav-side {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ overflow-x: hidden;
+ z-index: 999
+}
+
+.layui-bg-blue .layui-nav-bar, .layui-bg-blue .layui-nav-itemed:after, .layui-bg-blue .layui-this:after {
+ background-color: #93D1FF
+}
+
+.layui-bg-blue .layui-nav-child dd.layui-this {
+ background-color: #1E9FFF
+}
+
+.layui-bg-blue .layui-nav-itemed > a, .layui-nav-tree.layui-bg-blue .layui-nav-title a, .layui-nav-tree.layui-bg-blue .layui-nav-title a:hover {
+ background-color: #007DDB !important
+}
+
+.layui-breadcrumb {
+ visibility: hidden;
+ font-size: 0
+}
+
+.layui-breadcrumb > * {
+ font-size: 14px
+}
+
+.layui-breadcrumb a {
+ color: #999 !important
+}
+
+.layui-breadcrumb a:hover {
+ color: #5FB878 !important
+}
+
+.layui-breadcrumb a cite {
+ color: #666;
+ font-style: normal
+}
+
+.layui-breadcrumb span[lay-separator] {
+ margin: 0 10px;
+ color: #999
+}
+
+.layui-tab {
+ margin: 10px 0;
+ text-align: left !important
+}
+
+.layui-tab[overflow] > .layui-tab-title {
+ overflow: hidden
+}
+
+.layui-tab-title {
+ position: relative;
+ left: 0;
+ height: 40px;
+ white-space: nowrap;
+ font-size: 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-tab-title li {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle;
+ font-size: 14px;
+ transition: all .2s;
+ -webkit-transition: all .2s;
+ position: relative;
+ line-height: 40px;
+ min-width: 65px;
+ padding: 0 15px;
+ text-align: center;
+ cursor: pointer
+}
+
+.layui-tab-title li a {
+ display: block
+}
+
+.layui-tab-title .layui-this {
+ color: #000
+}
+
+.layui-tab-title .layui-this:after {
+ position: absolute;
+ left: 0;
+ top: 0;
+ content: '';
+ width: 100%;
+ height: 41px;
+ border-width: 1px;
+ border-style: solid;
+ border-bottom-color: #fff;
+ border-radius: 2px 2px 0 0;
+ box-sizing: border-box;
+ pointer-events: none
+}
+
+.layui-tab-bar {
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 10;
+ width: 30px;
+ height: 39px;
+ line-height: 39px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ text-align: center;
+ background-color: #fff;
+ cursor: pointer
+}
+
+.layui-tab-bar .layui-icon {
+ position: relative;
+ display: inline-block;
+ top: 3px;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-tab-item {
+ display: none
+}
+
+.layui-tab-more {
+ padding-right: 30px;
+ height: auto !important;
+ white-space: normal !important
+}
+
+.layui-tab-more li.layui-this:after {
+ border-bottom-color: #e2e2e2;
+ border-radius: 2px
+}
+
+.layui-tab-more .layui-tab-bar .layui-icon {
+ top: -2px;
+ top: 3px \9;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg)
+}
+
+:root .layui-tab-more .layui-tab-bar .layui-icon {
+ top: -2px \0/ IE9
+}
+
+.layui-tab-content {
+ padding: 10px
+}
+
+.layui-tab-title li .layui-tab-close {
+ position: relative;
+ display: inline-block;
+ width: 18px;
+ height: 18px;
+ line-height: 20px;
+ margin-left: 8px;
+ top: 1px;
+ text-align: center;
+ font-size: 14px;
+ color: #c2c2c2;
+ transition: all .2s;
+ -webkit-transition: all .2s
+}
+
+.layui-tab-title li .layui-tab-close:hover {
+ border-radius: 2px;
+ background-color: #FF5722;
+ color: #fff
+}
+
+.layui-tab-brief > .layui-tab-title .layui-this {
+ color: #009688
+}
+
+.layui-tab-brief > .layui-tab-more li.layui-this:after, .layui-tab-brief > .layui-tab-title .layui-this:after {
+ border: none;
+ border-radius: 0;
+ border-bottom: 2px solid #5FB878
+}
+
+.layui-tab-brief[overflow] > .layui-tab-title .layui-this:after {
+ top: -1px
+}
+
+.layui-tab-card {
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
+}
+
+.layui-tab-card > .layui-tab-title {
+ background-color: #f2f2f2
+}
+
+.layui-tab-card > .layui-tab-title li {
+ margin-right: -1px;
+ margin-left: -1px
+}
+
+.layui-tab-card > .layui-tab-title .layui-this {
+ background-color: #fff
+}
+
+.layui-tab-card > .layui-tab-title .layui-this:after {
+ border-top: none;
+ border-width: 1px;
+ border-bottom-color: #fff
+}
+
+.layui-tab-card > .layui-tab-title .layui-tab-bar {
+ height: 40px;
+ line-height: 40px;
+ border-radius: 0;
+ border-top: none;
+ border-right: none
+}
+
+.layui-tab-card > .layui-tab-more .layui-this {
+ background: 0 0;
+ color: #5FB878
+}
+
+.layui-tab-card > .layui-tab-more .layui-this:after {
+ border: none
+}
+
+.layui-timeline {
+ padding-left: 5px
+}
+
+.layui-timeline-item {
+ position: relative;
+ padding-bottom: 20px
+}
+
+.layui-timeline-axis {
+ position: absolute;
+ left: -5px;
+ top: 0;
+ z-index: 10;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ background-color: #fff;
+ color: #5FB878;
+ border-radius: 50%;
+ text-align: center;
+ cursor: pointer
+}
+
+.layui-timeline-axis:hover {
+ color: #FF5722
+}
+
+.layui-timeline-item:before {
+ content: '';
+ position: absolute;
+ left: 5px;
+ top: 0;
+ z-index: 0;
+ width: 1px;
+ height: 100%
+}
+
+.layui-timeline-item:last-child:before {
+ display: none
+}
+
+.layui-timeline-item:first-child:before {
+ display: block
+}
+
+.layui-timeline-content {
+ padding-left: 25px
+}
+
+.layui-timeline-title {
+ position: relative;
+ margin-bottom: 10px
+}
+
+.layui-badge, .layui-badge-dot, .layui-badge-rim {
+ position: relative;
+ display: inline-block;
+ padding: 0 6px;
+ font-size: 12px;
+ text-align: center;
+ background-color: #FF5722;
+ color: #fff;
+ border-radius: 2px
+}
+
+.layui-badge {
+ height: 18px;
+ line-height: 18px
+}
+
+.layui-badge-dot {
+ width: 8px;
+ height: 8px;
+ padding: 0;
+ border-radius: 50%
+}
+
+.layui-badge-rim {
+ height: 18px;
+ line-height: 18px;
+ border-width: 1px;
+ border-style: solid;
+ background-color: #fff;
+ color: #666
+}
+
+.layui-btn .layui-badge, .layui-btn .layui-badge-dot {
+ margin-left: 5px
+}
+
+.layui-nav .layui-badge, .layui-nav .layui-badge-dot {
+ position: absolute;
+ top: 50%;
+ margin: -8px 6px 0
+}
+
+.layui-tab-title .layui-badge, .layui-tab-title .layui-badge-dot {
+ left: 5px;
+ top: -2px
+}
+
+.layui-carousel {
+ position: relative;
+ left: 0;
+ top: 0;
+ background-color: #f8f8f8
+}
+
+.layui-carousel > [carousel-item] {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden
+}
+
+.layui-carousel > [carousel-item]:before {
+ position: absolute;
+ content: '\e63d';
+ left: 50%;
+ top: 50%;
+ width: 100px;
+ line-height: 20px;
+ margin: -10px 0 0 -50px;
+ text-align: center;
+ color: #c2c2c2;
+ font-family: layui-icon !important;
+ font-size: 30px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale
+}
+
+.layui-carousel > [carousel-item] > * {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #f8f8f8;
+ transition-duration: .3s;
+ -webkit-transition-duration: .3s
+}
+
+.layui-carousel-updown > * {
+ -webkit-transition: .3s ease-in-out up;
+ transition: .3s ease-in-out up
+}
+
+.layui-carousel-arrow {
+ display: none \9;
+ opacity: 0;
+ position: absolute;
+ left: 10px;
+ top: 50%;
+ margin-top: -18px;
+ width: 36px;
+ height: 36px;
+ line-height: 36px;
+ text-align: center;
+ font-size: 20px;
+ border: 0;
+ border-radius: 50%;
+ background-color: rgba(0, 0, 0, .2);
+ color: #fff;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s;
+ cursor: pointer
+}
+
+.layui-carousel-arrow[lay-type=add] {
+ left: auto !important;
+ right: 10px
+}
+
+.layui-carousel:hover .layui-carousel-arrow[lay-type=add], .layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add] {
+ right: 20px
+}
+
+.layui-carousel[lay-arrow=always] .layui-carousel-arrow {
+ opacity: 1;
+ left: 20px
+}
+
+.layui-carousel[lay-arrow=none] .layui-carousel-arrow {
+ display: none
+}
+
+.layui-carousel-arrow:hover, .layui-carousel-ind ul:hover {
+ background-color: rgba(0, 0, 0, .35)
+}
+
+.layui-carousel:hover .layui-carousel-arrow {
+ display: block \9;
+ opacity: 1;
+ left: 20px
+}
+
+.layui-carousel-ind {
+ position: relative;
+ top: -35px;
+ width: 100%;
+ line-height: 0 !important;
+ text-align: center;
+ font-size: 0
+}
+
+.layui-carousel[lay-indicator=outside] {
+ margin-bottom: 30px
+}
+
+.layui-carousel[lay-indicator=outside] .layui-carousel-ind {
+ top: 10px
+}
+
+.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul {
+ background-color: rgba(0, 0, 0, .5)
+}
+
+.layui-carousel[lay-indicator=none] .layui-carousel-ind {
+ display: none
+}
+
+.layui-carousel-ind ul {
+ display: inline-block;
+ padding: 5px;
+ background-color: rgba(0, 0, 0, .2);
+ border-radius: 10px;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s
+}
+
+.layui-carousel-ind li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 0 3px;
+ font-size: 14px;
+ background-color: #e2e2e2;
+ background-color: rgba(255, 255, 255, .5);
+ border-radius: 50%;
+ cursor: pointer;
+ -webkit-transition-duration: .3s;
+ transition-duration: .3s
+}
+
+.layui-carousel-ind li:hover {
+ background-color: rgba(255, 255, 255, .7)
+}
+
+.layui-carousel-ind li.layui-this {
+ background-color: #fff
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next, .layui-carousel > [carousel-item] > .layui-carousel-prev, .layui-carousel > [carousel-item] > .layui-this {
+ display: block
+}
+
+.layui-carousel > [carousel-item] > .layui-this {
+ left: 0
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-prev {
+ left: -100%
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next {
+ left: 100%
+}
+
+.layui-carousel > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ left: 0
+}
+
+.layui-carousel > [carousel-item] > .layui-this.layui-carousel-left {
+ left: -100%
+}
+
+.layui-carousel > [carousel-item] > .layui-this.layui-carousel-right {
+ left: 100%
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-arrow {
+ left: 50% !important;
+ top: 20px;
+ margin: 0 0 0 -18px
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > *, .layui-carousel[lay-anim=fade] > [carousel-item] > * {
+ left: 0 !important
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add] {
+ top: auto !important;
+ bottom: 20px
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind {
+ position: absolute;
+ top: 50%;
+ right: 20px;
+ width: auto;
+ height: auto
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind ul {
+ padding: 3px 5px
+}
+
+.layui-carousel[lay-anim=updown] .layui-carousel-ind li {
+ display: block;
+ margin: 6px 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this {
+ top: 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev {
+ top: -100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next {
+ top: 100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ top: 0
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-left {
+ top: -100%
+}
+
+.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-right {
+ top: 100%
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev {
+ opacity: 0
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {
+ opacity: 1
+}
+
+.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-right {
+ opacity: 0
+}
+
+.layui-fixbar {
+ position: fixed;
+ right: 15px;
+ bottom: 15px;
+ z-index: 999999
+}
+
+.layui-fixbar li {
+ width: 50px;
+ height: 50px;
+ line-height: 50px;
+ margin-bottom: 1px;
+ text-align: center;
+ cursor: pointer;
+ font-size: 30px;
+ background-color: #9F9F9F;
+ color: #fff;
+ border-radius: 2px;
+ opacity: .95
+}
+
+.layui-fixbar li:hover {
+ opacity: .85
+}
+
+.layui-fixbar li:active {
+ opacity: 1
+}
+
+.layui-fixbar .layui-fixbar-top {
+ display: none;
+ font-size: 40px
+}
+
+body .layui-util-face {
+ border: none;
+ background: 0 0
+}
+
+body .layui-util-face .layui-layer-content {
+ padding: 0;
+ background-color: #fff;
+ color: #666;
+ box-shadow: none
+}
+
+.layui-util-face .layui-layer-TipsG {
+ display: none
+}
+
+.layui-util-face ul {
+ position: relative;
+ width: 372px;
+ padding: 10px;
+ border: 1px solid #D9D9D9;
+ background-color: #fff;
+ box-shadow: 0 0 20px rgba(0, 0, 0, .2)
+}
+
+.layui-util-face ul li {
+ cursor: pointer;
+ float: left;
+ border: 1px solid #e8e8e8;
+ height: 22px;
+ width: 26px;
+ overflow: hidden;
+ margin: -1px 0 0 -1px;
+ padding: 4px 2px;
+ text-align: center
+}
+
+.layui-util-face ul li:hover {
+ position: relative;
+ z-index: 2;
+ border: 1px solid #eb7350;
+ background: #fff9ec
+}
+
+.layui-code {
+ position: relative;
+ margin: 10px 0;
+ padding: 15px;
+ line-height: 20px;
+ border: 1px solid #ddd;
+ border-left-width: 6px;
+ background-color: #F2F2F2;
+ color: #333;
+ font-family: Courier New;
+ font-size: 12px
+}
+
+.layui-rate, .layui-rate * {
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-rate {
+ padding: 10px 5px 10px 0;
+ font-size: 0
+}
+
+.layui-rate li i.layui-icon {
+ font-size: 20px;
+ color: #FFB800;
+ margin-right: 5px;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-rate li i:hover {
+ cursor: pointer;
+ transform: scale(1.12);
+ -webkit-transform: scale(1.12)
+}
+
+.layui-rate[readonly] li i:hover {
+ cursor: default;
+ transform: scale(1)
+}
+
+.layui-colorpicker {
+ width: 26px;
+ height: 26px;
+ border: 1px solid #e6e6e6;
+ padding: 5px;
+ border-radius: 2px;
+ line-height: 24px;
+ display: inline-block;
+ cursor: pointer;
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+.layui-colorpicker:hover {
+ border-color: #d2d2d2
+}
+
+.layui-colorpicker.layui-colorpicker-lg {
+ width: 34px;
+ height: 34px;
+ line-height: 32px
+}
+
+.layui-colorpicker.layui-colorpicker-sm {
+ width: 24px;
+ height: 24px;
+ line-height: 22px
+}
+
+.layui-colorpicker.layui-colorpicker-xs {
+ width: 22px;
+ height: 22px;
+ line-height: 20px
+}
+
+.layui-colorpicker-trigger-bgcolor {
+ display: block;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
+ border-radius: 2px
+}
+
+.layui-colorpicker-trigger-span {
+ display: block;
+ height: 100%;
+ box-sizing: border-box;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 2px;
+ text-align: center
+}
+
+.layui-colorpicker-trigger-i {
+ display: inline-block;
+ color: #FFF;
+ font-size: 12px
+}
+
+.layui-colorpicker-trigger-i.layui-icon-close {
+ color: #999
+}
+
+.layui-colorpicker-main {
+ position: absolute;
+ z-index: 66666666;
+ width: 280px;
+ padding: 7px;
+ background: #FFF;
+ border: 1px solid #d2d2d2;
+ border-radius: 2px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12)
+}
+
+.layui-colorpicker-main-wrapper {
+ height: 180px;
+ position: relative
+}
+
+.layui-colorpicker-basis {
+ width: 260px;
+ height: 100%;
+ position: relative
+}
+
+.layui-colorpicker-basis-white {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: linear-gradient(90deg, #FFF, hsla(0, 0%, 100%, 0))
+}
+
+.layui-colorpicker-basis-black {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: linear-gradient(0deg, #000, transparent)
+}
+
+.layui-colorpicker-basis-cursor {
+ width: 10px;
+ height: 10px;
+ border: 1px solid #FFF;
+ border-radius: 50%;
+ position: absolute;
+ top: -3px;
+ right: -3px;
+ cursor: pointer
+}
+
+.layui-colorpicker-side {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 12px;
+ height: 100%;
+ background: linear-gradient(red, #FF0, #0F0, #0FF, #00F, #F0F, red)
+}
+
+.layui-colorpicker-side-slider {
+ width: 100%;
+ height: 5px;
+ box-shadow: 0 0 1px #888;
+ box-sizing: border-box;
+ background: #FFF;
+ border-radius: 1px;
+ border: 1px solid #f0f0f0;
+ cursor: pointer;
+ position: absolute;
+ left: 0
+}
+
+.layui-colorpicker-main-alpha {
+ display: none;
+ height: 12px;
+ margin-top: 7px;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)
+}
+
+.layui-colorpicker-alpha-bgcolor {
+ height: 100%;
+ position: relative
+}
+
+.layui-colorpicker-alpha-slider {
+ width: 5px;
+ height: 100%;
+ box-shadow: 0 0 1px #888;
+ box-sizing: border-box;
+ background: #FFF;
+ border-radius: 1px;
+ border: 1px solid #f0f0f0;
+ cursor: pointer;
+ position: absolute;
+ top: 0
+}
+
+.layui-colorpicker-main-pre {
+ padding-top: 7px;
+ font-size: 0
+}
+
+.layui-colorpicker-pre {
+ width: 20px;
+ height: 20px;
+ border-radius: 2px;
+ display: inline-block;
+ margin-left: 6px;
+ margin-bottom: 7px;
+ cursor: pointer
+}
+
+.layui-colorpicker-pre:nth-child(11n+1) {
+ margin-left: 0
+}
+
+.layui-colorpicker-pre-isalpha {
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)
+}
+
+.layui-colorpicker-pre.layui-this {
+ box-shadow: 0 0 3px 2px rgba(0, 0, 0, .15)
+}
+
+.layui-colorpicker-pre > div {
+ height: 100%;
+ border-radius: 2px
+}
+
+.layui-colorpicker-main-input {
+ text-align: right;
+ padding-top: 7px
+}
+
+.layui-colorpicker-main-input .layui-btn-container .layui-btn {
+ margin: 0 0 0 10px
+}
+
+.layui-colorpicker-main-input div.layui-inline {
+ float: left;
+ margin-right: 10px;
+ font-size: 14px
+}
+
+.layui-colorpicker-main-input input.layui-input {
+ width: 150px;
+ height: 30px;
+ color: #666
+}
+
+.layui-slider {
+ height: 4px;
+ background: #e2e2e2;
+ border-radius: 3px;
+ position: relative;
+ cursor: pointer
+}
+
+.layui-slider-bar {
+ border-radius: 3px;
+ position: absolute;
+ height: 100%
+}
+
+.layui-slider-step {
+ position: absolute;
+ top: 0;
+ width: 4px;
+ height: 4px;
+ border-radius: 50%;
+ background: #FFF;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%)
+}
+
+.layui-slider-wrap {
+ width: 36px;
+ height: 36px;
+ position: absolute;
+ top: -16px;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ z-index: 10;
+ text-align: center
+}
+
+.layui-slider-wrap-btn {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background: #FFF;
+ display: inline-block;
+ vertical-align: middle;
+ cursor: pointer;
+ transition: .3s
+}
+
+.layui-slider-wrap:after {
+ content: "";
+ height: 100%;
+ display: inline-block;
+ vertical-align: middle
+}
+
+.layui-slider-wrap-btn.layui-slider-hover, .layui-slider-wrap-btn:hover {
+ transform: scale(1.2)
+}
+
+.layui-slider-wrap-btn.layui-disabled:hover {
+ transform: scale(1) !important
+}
+
+.layui-slider-tips {
+ position: absolute;
+ top: -42px;
+ z-index: 66666666;
+ white-space: nowrap;
+ display: none;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ color: #FFF;
+ background: #000;
+ border-radius: 3px;
+ height: 25px;
+ line-height: 25px;
+ padding: 0 10px
+}
+
+.layui-slider-tips:after {
+ content: '';
+ position: absolute;
+ bottom: -12px;
+ left: 50%;
+ margin-left: -6px;
+ width: 0;
+ height: 0;
+ border-width: 6px;
+ border-style: solid;
+ border-color: #000 transparent transparent
+}
+
+.layui-slider-input {
+ width: 70px;
+ height: 32px;
+ border: 1px solid #e6e6e6;
+ border-radius: 3px;
+ font-size: 16px;
+ line-height: 32px;
+ position: absolute;
+ right: 0;
+ top: -15px
+}
+
+.layui-slider-input-btn {
+ display: none;
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 20px;
+ height: 100%;
+ border-left: 1px solid #d2d2d2
+}
+
+.layui-slider-input-btn i {
+ cursor: pointer;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ width: 20px;
+ height: 50%;
+ font-size: 12px;
+ line-height: 16px;
+ text-align: center;
+ color: #999
+}
+
+.layui-slider-input-btn i:first-child {
+ top: 0;
+ border-bottom: 1px solid #d2d2d2
+}
+
+.layui-slider-input-txt {
+ height: 100%;
+ font-size: 14px
+}
+
+.layui-slider-input-txt input {
+ height: 100%;
+ border: none
+}
+
+.layui-slider-input-btn i:hover {
+ color: #009688
+}
+
+.layui-slider-vertical {
+ width: 4px;
+ margin-left: 34px
+}
+
+.layui-slider-vertical .layui-slider-bar {
+ width: 4px
+}
+
+.layui-slider-vertical .layui-slider-step {
+ top: auto;
+ left: 0;
+ -webkit-transform: translateY(50%);
+ transform: translateY(50%)
+}
+
+.layui-slider-vertical .layui-slider-wrap {
+ top: auto;
+ left: -16px;
+ -webkit-transform: translateY(50%);
+ transform: translateY(50%)
+}
+
+.layui-slider-vertical .layui-slider-tips {
+ top: auto;
+ left: 2px
+}
+
+@media \0screen {
+ .layui-slider-wrap-btn {
+ margin-left: -20px
+ }
+
+ .layui-slider-vertical .layui-slider-wrap-btn {
+ margin-left: 0;
+ margin-bottom: -20px
+ }
+
+ .layui-slider-vertical .layui-slider-tips {
+ margin-left: -8px
+ }
+
+ .layui-slider > span {
+ margin-left: 8px
+ }
+}
+
+.layui-anim {
+ -webkit-animation-duration: .3s;
+ animation-duration: .3s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both
+}
+
+.layui-anim.layui-icon {
+ display: inline-block
+}
+
+.layui-anim-loop {
+ -webkit-animation-iteration-count: infinite;
+ animation-iteration-count: infinite
+}
+
+.layui-trans, .layui-trans a {
+ transition: all .3s;
+ -webkit-transition: all .3s
+}
+
+@-webkit-keyframes layui-rotate {
+ from {
+ -webkit-transform: rotate(0)
+ }
+ to {
+ -webkit-transform: rotate(360deg)
+ }
+}
+
+@keyframes layui-rotate {
+ from {
+ transform: rotate(0)
+ }
+ to {
+ transform: rotate(360deg)
+ }
+}
+
+.layui-anim-rotate {
+ -webkit-animation-name: layui-rotate;
+ animation-name: layui-rotate;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear
+}
+
+@-webkit-keyframes layui-up {
+ from {
+ -webkit-transform: translate3d(0, 100%, 0);
+ opacity: .3
+ }
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+@keyframes layui-up {
+ from {
+ transform: translate3d(0, 100%, 0);
+ opacity: .3
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+.layui-anim-up {
+ -webkit-animation-name: layui-up;
+ animation-name: layui-up
+}
+
+@-webkit-keyframes layui-upbit {
+ from {
+ -webkit-transform: translate3d(0, 30px, 0);
+ opacity: .3
+ }
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+@keyframes layui-upbit {
+ from {
+ transform: translate3d(0, 30px, 0);
+ opacity: .3
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ opacity: 1
+ }
+}
+
+.layui-anim-upbit {
+ -webkit-animation-name: layui-upbit;
+ animation-name: layui-upbit
+}
+
+@-webkit-keyframes layui-scale {
+ 0% {
+ opacity: .3;
+ -webkit-transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1)
+ }
+}
+
+@keyframes layui-scale {
+ 0% {
+ opacity: .3;
+ -ms-transform: scale(.5);
+ transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: scale(1);
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scale {
+ -webkit-animation-name: layui-scale;
+ animation-name: layui-scale
+}
+
+@-webkit-keyframes layui-scale-spring {
+ 0% {
+ opacity: .5;
+ -webkit-transform: scale(.5)
+ }
+ 80% {
+ opacity: .8;
+ -webkit-transform: scale(1.1)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1)
+ }
+}
+
+@keyframes layui-scale-spring {
+ 0% {
+ opacity: .5;
+ transform: scale(.5)
+ }
+ 80% {
+ opacity: .8;
+ transform: scale(1.1)
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1)
+ }
+}
+
+.layui-anim-scaleSpring {
+ -webkit-animation-name: layui-scale-spring;
+ animation-name: layui-scale-spring
+}
+
+@-webkit-keyframes layui-fadein {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+
+@keyframes layui-fadein {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+
+.layui-anim-fadein {
+ -webkit-animation-name: layui-fadein;
+ animation-name: layui-fadein
+}
+
+@-webkit-keyframes layui-fadeout {
+ 0% {
+ opacity: 1
+ }
+ 100% {
+ opacity: 0
+ }
+}
+
+@keyframes layui-fadeout {
+ 0% {
+ opacity: 1
+ }
+ 100% {
+ opacity: 0
+ }
+}
+
+.layui-anim-fadeout {
+ -webkit-animation-name: layui-fadeout;
+ animation-name: layui-fadeout
+}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/layui.mobile.css b/src/main/resources/static/layui/css/layui.mobile.css
new file mode 100644
index 0000000..6f7f0a1
--- /dev/null
+++ b/src/main/resources/static/layui/css/layui.mobile.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,legend,li,ol,p,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}html{font:12px 'Helvetica Neue','PingFang SC',STHeitiSC-Light,Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0)}a{text-decoration:none;background:0 0}a:active,a:hover{outline:0}table{border-collapse:collapse;border-spacing:0}li{list-style:none}b,strong{font-weight:700}h1,h2,h3,h4,h5,h6{font-weight:500}address,cite,dfn,em,var{font-style:normal}dfn{font-style:italic}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}img{border:0;vertical-align:bottom}.layui-inline,input,label{vertical-align:middle}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;outline:0}button,select{text-transform:none}select{-webkit-appearance:none;border:none}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=1.0.7);src:url(../font/iconfont.eot?v=1.0.7#iefix) format('embedded-opentype'),url(../font/iconfont.woff?v=1.0.7) format('woff'),url(../font/iconfont.ttf?v=1.0.7) format('truetype'),url(../font/iconfont.svg?v=1.0.7#iconfont) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-box,.layui-box *{-webkit-box-sizing:content-box!important;-moz-box-sizing:content-box!important;box-sizing:content-box!important}.layui-border-box,.layui-border-box *{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1}.layui-edge,.layui-upload-iframe{position:absolute;width:0;height:0}.layui-edge{border-style:dashed;border-color:transparent;overflow:hidden}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:active{background-color:#d2d2d2!important;color:#fff!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-upload-iframe{border:0;visibility:hidden}.layui-upload-enter{border:1px solid #009E94;background-color:#009E94;color:#fff;-webkit-transform:scale(1.1);transform:scale(1.1)}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}@-webkit-keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-left{-webkit-animation-name:layui-m-anim-left;animation-name:layui-m-anim-left}@-webkit-keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-right{-webkit-animation-name:layui-m-anim-right;animation-name:layui-m-anim-right}@-webkit-keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.layui-m-anim-lout{-webkit-animation-name:layui-m-anim-lout;animation-name:layui-m-anim-lout}@-webkit-keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}.layui-m-anim-rout{-webkit-animation-name:layui-m-anim-rout;animation-name:layui-m-anim-rout}.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/code.css b/src/main/resources/static/layui/css/modules/code.css
new file mode 100644
index 0000000..d0d3822
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/code.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/laydate/default/laydate.css b/src/main/resources/static/layui/css/modules/laydate/default/laydate.css
new file mode 100644
index 0000000..f7e690e
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/laydate/default/laydate.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ .laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:laydate-upbit;animation-name:laydate-upbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@-webkit-keyframes laydate-upbit{from{-webkit-transform:translate3d(0,20px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes laydate-upbit{from{transform:translate3d(0,20px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-0 .laydate-next-m,.layui-laydate-range .laydate-main-list-0 .laydate-next-y,.layui-laydate-range .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#00F7DE}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eaeaea;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/layer/default/icon-ext.png b/src/main/resources/static/layui/css/modules/layer/default/icon-ext.png
new file mode 100644
index 0000000..bbbb669
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layer/default/icon-ext.png differ
diff --git a/src/main/resources/static/layui/css/modules/layer/default/icon.png b/src/main/resources/static/layui/css/modules/layer/default/icon.png
new file mode 100644
index 0000000..3e17da8
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layer/default/icon.png differ
diff --git a/src/main/resources/static/layui/css/modules/layer/default/layer.css b/src/main/resources/static/layui/css/modules/layer/default/layer.css
new file mode 100644
index 0000000..157d537
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layer/default/layer.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ .layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/layer/default/loading-0.gif b/src/main/resources/static/layui/css/modules/layer/default/loading-0.gif
new file mode 100644
index 0000000..6f3c953
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layer/default/loading-0.gif differ
diff --git a/src/main/resources/static/layui/css/modules/layer/default/loading-1.gif b/src/main/resources/static/layui/css/modules/layer/default/loading-1.gif
new file mode 100644
index 0000000..db3a483
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layer/default/loading-1.gif differ
diff --git a/src/main/resources/static/layui/css/modules/layer/default/loading-2.gif b/src/main/resources/static/layui/css/modules/layer/default/loading-2.gif
new file mode 100644
index 0000000..5bb90fd
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layer/default/loading-2.gif differ
diff --git a/src/main/resources/static/layui/css/modules/layim/html/chatlog.html b/src/main/resources/static/layui/css/modules/layim/html/chatlog.html
new file mode 100644
index 0000000..9cbc571
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/html/chatlog.html
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+聊天记录
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/static/layui/css/modules/layim/html/find.html b/src/main/resources/static/layui/css/modules/layim/html/find.html
new file mode 100644
index 0000000..ff5cab1
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/html/find.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+发现
+
+
+
+
+
+
+
+
此为自定义的【查找】页面,因需求不一,所以官方暂不提供该模版结构与样式,实际使用时,可移至该文件到你的项目中,对页面自行把控。
+ 文件所在目录(相对于layui.js):/css/modules/layim/html/find.html
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/static/layui/css/modules/layim/html/getmsg.json b/src/main/resources/static/layui/css/modules/layim/html/getmsg.json
new file mode 100644
index 0000000..3d9b9d4
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/html/getmsg.json
@@ -0,0 +1,87 @@
+{
+ "code": 0,
+ "pages": 1,
+ "data": [
+ {
+ "id": 76,
+ "content": "申请添加你为好友",
+ "uid": 168,
+ "from": 166488,
+ "from_group": 0,
+ "type": 1,
+ "remark": "有问题要问",
+ "href": null,
+ "read": 1,
+ "time": "刚刚",
+ "user": {
+ "id": 166488,
+ "avatar": "http://q.qlogo.cn/qqapp/101235792/B704597964F9BD0DB648292D1B09F7E8/100",
+ "username": "李彦宏",
+ "sign": null
+ }
+ },
+ {
+ "id": 75,
+ "content": "申请添加你为好友",
+ "uid": 168,
+ "from": 347592,
+ "from_group": 0,
+ "type": 1,
+ "remark": "你好啊!",
+ "href": null,
+ "read": 1,
+ "time": "刚刚",
+ "user": {
+ "id": 347592,
+ "avatar": "http://q.qlogo.cn/qqapp/101235792/B78751375E0531675B1272AD994BA875/100",
+ "username": "麻花疼",
+ "sign": null
+ }
+ },
+ {
+ "id": 62,
+ "content": "雷军 拒绝了你的好友申请",
+ "uid": 168,
+ "from": null,
+ "from_group": null,
+ "type": 1,
+ "remark": null,
+ "href": null,
+ "read": 1,
+ "time": "10天前",
+ "user": {
+ "id": null
+ }
+ },
+ {
+ "id": 60,
+ "content": "马小云 已经同意你的好友申请",
+ "uid": 168,
+ "from": null,
+ "from_group": null,
+ "type": 1,
+ "remark": null,
+ "href": null,
+ "read": 1,
+ "time": "10天前",
+ "user": {
+ "id": null
+ }
+ },
+ {
+ "id": 61,
+ "content": "贤心 已经同意你的好友申请",
+ "uid": 168,
+ "from": null,
+ "from_group": null,
+ "type": 1,
+ "remark": null,
+ "href": null,
+ "read": 1,
+ "time": "10天前",
+ "user": {
+ "id": null
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/layim/html/msgbox.html b/src/main/resources/static/layui/css/modules/layim/html/msgbox.html
new file mode 100644
index 0000000..0adf002
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/html/msgbox.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+消息盒子
+
+
+
+
+
+
+
+
+
+
注意:这些都是模拟数据,实际使用时,需将其中的模拟接口改为你的项目真实接口。
+ 该模版文件所在目录(相对于layui.js):/css/modules/layim/html/msgbox.html
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/static/layui/css/modules/layim/layim.css b/src/main/resources/static/layui/css/modules/layim/layim.css
new file mode 100644
index 0000000..69ad58a
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/layim.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ html #layuicss-skinlayimcss{display:none;position:absolute;width:1989px}body .layui-layim,body .layui-layim-chat{border:1px solid #D9D9D9;border-color:rgba(0,0,0,.05);background-repeat:no-repeat;background-color:#F6F6F6;color:#333;font-family:\5FAE\8F6F\96C5\9ED1}body .layui-layim-chat{background-size:cover}body .layui-layim .layui-layer-title{height:110px;border-bottom:none;background:0 0}.layui-layim-main{position:relative;top:-98px;left:0}body .layui-layim .layui-layer-content,body .layui-layim-chat .layui-layer-content{overflow:visible}.layui-layim cite,.layui-layim em,.layui-layim-chat cite,.layui-layim-chat em{font-style:normal}.layui-layim-info{height:50px;font-size:0;padding:0 15px}.layui-layim-info *{font-size:14px}.layim-tab-content li h5 *,.layui-layim-info div,.layui-layim-skin li,.layui-layim-tab li,.layui-layim-tool li{display:inline-block;vertical-align:top;*zoom:1;*display:inline}.layim-tab-content li h5 span,.layui-layim-info .layui-layim-user,.layui-layim-list li p,.layui-layim-list li span,.layui-layim-remark{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.layui-layim-info .layui-layim-user{max-width:150px;margin-right:5px;font-size:16px}.layui-layim-status{position:relative;top:2px;line-height:19px;cursor:pointer}.layim-status-online{color:#3FDD86}.layim-status-hide{color:#DD691D}.layim-menu-box{display:none;position:absolute;z-index:100;top:24px;left:-31px;padding:5px 0;width:85px;border:1px solid #E2E2E2;border-radius:2px;background-color:#fff;box-shadow:1px 1px 20px rgba(0,0,0,.1)}.layim-menu-box li{position:relative;line-height:22px;padding-left:30px;font-size:12px}.layim-menu-box li cite{padding-right:5px;font-size:14px}.layim-menu-box li i{display:none;position:absolute;left:8px;top:0;font-weight:700;color:#5FB878}.layim-menu-box .layim-this i{display:block}.layim-menu-box li:hover{background-color:#eee}.layui-layim-remark{position:relative;left:-6px;display:block;width:100%;border:1px solid transparent;margin-top:8px;padding:0 5px;height:26px;line-height:26px;background:0 0;border-radius:2px}.layui-layim-remark:focus,.layui-layim-remark:hover{border:1px solid #d2d2d2;border-color:rgba(0,0,0,.15)}.layui-layim-remark:focus{background-color:#fff}.layui-layim-tab{margin-top:10px;padding:9px 0;font-size:0}.layui-layim-tab li{position:relative;width:33.33%;height:24px;line-height:24px;font-size:22px;text-align:center;color:#666;color:rgba(0,0,0,.6);cursor:pointer}.layim-tab-two li{width:50%}.layui-layim-tab li.layim-this:after{content:'';position:absolute;left:0;bottom:-9px;width:100%;height:3px;background-color:#3FDD86}.layui-layim-tab li.layim-hide{display:none}.layui-layim-tab li:hover{opacity:.8;filter:Alpha(opacity=80)}.layim-tab-content{display:none;padding:10px 0;height:349px;overflow:hidden;background-color:#fff;background-color:rgba(255,255,255,.9)}.layim-tab-content:hover{overflow-y:auto}.layim-tab-content li h5{position:relative;margin-right:15px;padding-left:30px;height:28px;line-height:28px;cursor:pointer;font-size:0;white-space:nowrap;overflow:hidden}.layim-tab-content li h5 *{font-size:14px}.layim-tab-content li h5 span{max-width:125px}.layim-tab-content li h5 i{position:absolute;left:12px;top:0;color:#C9BDBB}.layim-tab-content li h5 em{padding-left:5px;color:#999}.layim-tab-content li h5[lay-type=true] i{top:2px}.layim-tab-content li ul{display:none;margin-bottom:10px}.layui-layim-list li{position:relative;height:42px;padding:5px 15px 5px 60px;font-size:0;cursor:pointer}.layui-layim-list li:hover{background-color:#F2F2F2;background-color:rgba(0,0,0,.05)}.layui-layim-list li.layim-null{height:20px;line-height:20px;padding:0;font-size:14px;color:#999;text-align:center;cursor:default}.layui-layim-list li.layim-null:hover{background:0 0}.layui-layim-list li *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px}.layui-layim-list li span{margin-top:4px;max-width:155px}.layui-layim-list li img{position:absolute;left:15px;top:8px;width:36px;height:36px;border-radius:100%}.layui-layim-list li p{display:block;padding-right:30px;line-height:18px;font-size:12px;color:#999}.layui-layim-list li .layim-msg-status{display:none;position:absolute;right:10px;bottom:7px;padding:0 5px;height:16px;line-height:16px;border-radius:16px;text-align:center;font-size:10px;background-color:#F74C31;color:#fff}.layim-list-gray{-webkit-filter:grayscale(100%);-ms-filter:grayscale(100%);filter:grayscale(100%);filter:gray}.layui-layim-tool{padding:0 10px;font-size:0;background-color:#F6F6F6;border-radius:0 0 2px 2px}.layui-layim-tool li{position:relative;width:48px;height:37px;line-height:40px;text-align:center;font-size:22px;cursor:pointer}.layui-layim-tool li:active{background-color:#e2e2e2}.layui-layim-tool .layim-tool-msgbox{line-height:37px}.layui-layim-tool .layim-tool-find{line-height:38px}.layui-layim-tool .layim-tool-skin{font-size:26px}.layim-tool-msgbox span{display:none;position:absolute;left:12px;top:-12px;height:20px;line-height:20px;padding:0 10px;border-radius:2px;background-color:#33DF83;color:#fff;font-size:12px;-webkit-animation-duration:1s;animation-duration:1s}.layim-tool-msgbox .layer-anim-05{display:block}.layui-layim-search{display:none;position:absolute;bottom:5px;left:5px;height:28px;line-height:28px}.layui-layim-search input{width:210px;padding:0 30px 0 10px;height:30px;line-height:30px;border:none;border-radius:3px;background-color:#ddd}.layui-layim-search label{position:absolute;right:6px;top:4px;font-size:20px;cursor:pointer;color:#333;font-weight:400}.layui-layim-skin{margin:10px 0 0 10px;font-size:0}.layui-layim-skin li{margin:0 10px 10px 0;line-height:60px;text-align:center;background-color:#f6f6f6}.layui-layim-skin li,.layui-layim-skin li img{width:86px;height:60px;cursor:pointer}.layui-layim-skin li img:hover{opacity:.8;filter:Alpha(opacity=80)}.layui-layim-skin li cite{font-size:14px;font-style:normal}body .layui-layim-chat{background-color:#fff}body .layui-layim-chat-list{width:760px}body .layui-layim-chat .layui-layer-title{height:80px;border-bottom:none;background-color:#F8F8F8;background-color:rgba(245,245,245,.7)}body .layui-layim-chat .layui-layer-content{background:0 0}.layim-chat-list li *,.layui-layim-min .layui-layer-content *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px}.layim-chat-list{display:none;position:absolute;z-index:1000;top:-80px;width:200px;height:100%;background-color:#D9D9D9;overflow:hidden;font-size:0}.layim-chat-list:hover{overflow-y:auto}.layim-chat-list li,.layui-layim-min .layui-layer-content{position:relative;margin:5px;padding:5px 30px 5px 5px;line-height:40px;cursor:pointer;border-radius:3px}.layim-chat-list li img,.layui-layim-min .layui-layer-content img{width:40px;height:40px;border-radius:100%}.layui-layim-photos{cursor:crosshair}.layim-chat-list li{white-space:nowrap}.layim-chat-list li span,.layui-layim-min .layui-layer-content span{width:100px;padding-left:10px;font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layim-chat-list li span cite{color:#999;padding-left:10px}.layim-chat-list li:hover{background-color:#E2E2E2}.layim-chat-list li.layim-this{background-color:#F3F3F3}.layim-chat-list li .layui-icon{display:none;position:absolute;right:5px;top:7px;color:#555;font-size:22px}.layim-chat-list li .layui-icon:hover{color:#c00}.layim-chat-list li:hover .layui-icon{display:inline-block}.layim-chat-system{margin:10px 0;text-align:center}.layim-chat-system span{display:inline-block;line-height:30px;padding:0 15px;border-radius:3px;background-color:#e2e2e2;cursor:default;font-size:14px}.layim-chat{display:none;position:relative;background-color:#fff;background-color:rgba(255,255,255,.9)}.layim-chat-title{position:absolute;top:-80px;height:80px}.layim-chat-other{position:relative;top:15px;left:15px;padding-left:60px;cursor:default}.layim-chat-other img{position:absolute;left:0;top:0;width:50px;height:50px;border-radius:100%}.layim-chat-username{position:relative;top:5px;font-size:18px}.layim-chat-status{margin-top:6px;font-size:14px;color:#999}.layim-chat-group .layim-chat-other .layim-chat-username{cursor:pointer}.layim-chat-group .layim-chat-other .layim-chat-username em{padding:0 10px;color:#999}.layim-chat-main{height:262px;padding:15px 15px 5px;overflow-x:hidden;overflow-y:auto}.layim-chat-main ul li{position:relative;font-size:0;margin-bottom:10px;padding-left:60px;min-height:68px}.layim-chat-text,.layim-chat-user{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px}.layim-chat-user{position:absolute;left:3px}.layim-chat-user img{width:40px;height:40px;border-radius:100%}.layim-chat-user cite{position:absolute;left:60px;top:-2px;width:500px;line-height:24px;font-size:12px;white-space:nowrap;color:#999;text-align:left;font-style:normal}.layim-chat-user cite i{padding-left:15px;font-style:normal}.layim-chat-text{position:relative;line-height:22px;margin-top:25px;padding:8px 15px;background-color:#e2e2e2;border-radius:3px;color:#333;word-break:break-all;max-width:462px\9}.layim-chat-text:after{content:'';position:absolute;left:-10px;top:13px;width:0;height:0;border-style:solid dashed dashed;border-color:#e2e2e2 transparent transparent;overflow:hidden;border-width:10px}.layim-chat-text a{color:#33DF83}.layim-chat-text img{max-width:100%;vertical-align:middle}.layim-chat-text .layui-layim-file,.layui-layim-file{display:block;text-align:center}.layim-chat-text .layui-layim-file{color:#333}.layui-layim-file:hover{opacity:.9}.layui-layim-file i{font-size:80px;line-height:80px}.layui-layim-file cite{display:block;line-height:20px;font-size:14px}.layui-layim-audio{text-align:center;cursor:pointer}.layui-layim-audio .layui-icon{position:relative;top:5px;font-size:24px}.layui-layim-audio p{margin-top:3px}.layui-layim-video{width:120px;height:80px;line-height:80px;background-color:#333;text-align:center;border-radius:3px}.layui-layim-video .layui-icon{font-size:36px;cursor:pointer;color:#fff}.layim-chat-main ul .layim-chat-system{min-height:0;padding:0}.layim-chat-main ul .layim-chat-mine{text-align:right;padding-left:0;padding-right:60px}.layim-chat-mine .layim-chat-user{left:auto;right:3px}.layim-chat-mine .layim-chat-user cite{left:auto;right:60px;text-align:right}.layim-chat-mine .layim-chat-user cite i{padding-left:0;padding-right:15px}.layim-chat-mine .layim-chat-text{margin-left:0;text-align:left;background-color:#5FB878;color:#fff}.layim-chat-mine .layim-chat-text:after{left:auto;right:-10px;border-top-color:#5FB878}.layim-chat-mine .layim-chat-text a{color:#fff}.layim-chat-footer{border-top:1px solid #F1F1F1}.layim-chat-tool{position:relative;padding:0 8px;height:38px;line-height:38px;font-size:0}.layim-chat-tool span{position:relative;margin:0 10px;display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:24px;cursor:pointer}.layim-chat-tool .layim-tool-log{position:absolute;right:5px;font-size:14px}.layim-tool-log i{position:relative;top:2px;margin-right:5px;font-size:20px;color:#999}.layim-tool-image input{position:absolute;font-size:0;left:0;top:0;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}body .layui-layim-face{margin:10px 0 0 -18px;border:none;background:0 0}body .layui-layim-face .layui-layer-content{padding:0;background-color:#fff;color:#666;box-shadow:none}.layui-layim-face .layui-layer-TipsG{display:none}.layui-layim-face ul{position:relative;width:372px;padding:10px;border:1px solid #D9D9D9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-layim-face ul li{cursor:pointer;float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px;text-align:center}.layui-layim-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layim-chat-textarea{margin-left:10px}.layim-chat-textarea textarea{display:block;width:100%;padding:5px 0 0;height:68px;line-height:20px;border:none;overflow:auto;resize:none;background:0 0}.layim-chat-textarea textarea:focus{outline:0}.layim-chat-bottom{position:relative;height:46px}.layim-chat-send{position:absolute;right:15px;top:3px;height:32px;line-height:32px;font-size:0;cursor:pointer}.layim-chat-send span{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px;line-height:32px;margin-left:5px;padding:0 20px;background-color:#5FB878;color:#fff;border-radius:3px}.layim-chat-send span:hover{background-color:#69BC80}.layim-chat-send span:active{background-color:#59B573}.layim-chat-send .layim-send-btn{border-radius:3px 0 0 3px}.layim-chat-send .layim-send-set{position:relative;width:30px;height:32px;margin-left:0;padding:0;border-left:1px solid #85C998;border-radius:0 3px 3px 0}.layim-send-set .layui-edge{position:absolute;top:14px;left:9px;border-width:6px;border-top-style:solid;border-top-color:#fff}.layim-chat-send .layim-menu-box{left:auto;right:0;top:33px;width:180px;padding:10px 0}.layim-chat-send .layim-menu-box li{padding-right:15px;line-height:28px}body .layui-layim-min{border:1px solid #D9D9D9}.layui-layim-min .layui-layer-content{margin:0 5px;padding:5px 10px;white-space:nowrap}.layui-layim-close .layui-layer-content span{width:auto;max-width:120px}body .layui-layim-members{margin:25px 0 0 -75px;border:none;background:0 0}body .layui-layim-members .layui-layer-content{padding:0;background:0 0;color:#666;box-shadow:none}.layui-layim-members .layui-layer-TipsG{display:none}.layui-layim-members ul{position:relative;width:578px;height:200px;padding:10px 10px 0;border:1px solid #D9D9D9;background-color:#fff;background-color:rgba(255,255,255,.9);box-shadow:none;overflow:hidden;font-size:0}.layui-layim-members ul:hover{overflow:auto}.layim-add-img,.layim-add-remark,.layui-layim-members li{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px}.layui-layim-members li{width:112px;margin:10px 0;text-align:center}.layui-layim-members li a{position:relative;display:inline-block;max-width:100%}.layui-layim-members li a:after{content:'';position:absolute;width:46px;height:46px;left:50%;margin-left:-23px;top:0;border:1px solid #eee;border-color:rgba(0,0,0,.1);border-radius:100%}.layui-layim-members li img{width:48px;height:48px;border-radius:100%}.layui-layim-members li:hover{opacity:.9}.layui-layim-members li a cite{display:block;padding:0 3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}body .layui-layim-contextmenu{margin:70px 0 0 30px;width:200px;padding:5px 0;border:1px solid #ccc;background:#fff;border-radius:0;box-shadow:0 0 5px rgba(0,0,0,.2)}body .layui-layim-contextmenu .layui-layer-content{padding:0;background-color:#fff;color:#333;font-size:14px;box-shadow:none}.layui-layim-contextmenu .layui-layer-TipsG{display:none}.layui-layim-contextmenu li{padding:0 15px 0 35px;cursor:pointer;line-height:30px}.layui-layim-contextmenu li:hover{background-color:#F2F2F2}.layim-add-box{margin:15px;font-size:0}.layim-add-img img,.layim-add-remark p{margin-bottom:10px}.layim-add-img{width:100px;margin-right:20px;text-align:center}.layim-add-img img{width:100px;height:100px}.layim-add-remark{width:280px}.layim-add-remark .layui-select{width:100%;margin-bottom:10px}.layim-add-remark .layui-textarea{height:80px;min-height:80px;resize:none}.layim-tab-content,.layui-layim-face ul,.layui-layim-tab{margin-bottom:0}.layim-tab-content li h5{margin-top:0;margin-bottom:0},.layui-layim-face img{vertical-align:bottom}.layim-chat-other span{color:#444}.layim-chat-other span cite{padding:0 15px;color:#999}.layim-chat-other:hover{text-decoration:none}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/layim/mobile/layim.css b/src/main/resources/static/layui/css/modules/layim/mobile/layim.css
new file mode 100644
index 0000000..129721b
--- /dev/null
+++ b/src/main/resources/static/layui/css/modules/layim/mobile/layim.css
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ .layim-tab-content li h5,.layui-layim-list li{border-bottom:1px solid #f2f2f2;cursor:pointer}html #layuicss-skinlayim-mobilecss{display:none;position:absolute;width:1989px}.layim-tab-content li h5 *,.layui-layim-skin li,.layui-layim-tab li,.layui-layim-tool li{display:inline-block;vertical-align:top;*zoom:1;*display:inline}.layim-tab-content li h5 span,.layui-layim-list li p,.layui-layim-list li span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.layui-layim-tab{position:absolute;bottom:0;left:0;right:0;height:50px;border-top:1px solid #f2f2f2;background-color:#fff}.layui-layim-tab li{position:relative;width:33.33%;height:50px;text-align:center;color:#666;color:rgba(0,0,0,.6);cursor:pointer}.layui-layim-tab li .layui-icon{position:relative;top:7px;font-size:25px}.layui-layim-tab li span{position:relative;bottom:-3px;display:block;font-size:12px}.layui-layim-tab li[lay-type=more] .layui-icon{top:4px;font-size:22px}.layui-layim-tab li.layim-this{color:#3FDD86}.layim-new{display:none;position:absolute;top:5px;left:50%;margin-left:15px;width:10px;height:10px;border-radius:10px;background-color:#F74C31;color:#fff}.layim-list-top .layim-new{position:relative;vertical-align:top;top:10px;left:initial;margin-left:5px}.layim-list-top i.layui-show{display:inline-block!important}.layim-tab-content,.layim-tab-content li ul{display:none}.layui-layim{position:fixed;left:0;right:0;top:50px;bottom:50px;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch}.layim-tab-content li h5{position:relative;padding-left:35px;height:45px;line-height:45px;font-size:0;white-space:nowrap;overflow:hidden}.layim-tab-content li h5 *{font-size:17px}.layim-tab-content li h5 span{max-width:80%}.layim-tab-content li h5 i{position:absolute;left:12px;top:0;color:#C9BDBB}.layim-tab-content li h5 em{padding-left:5px;color:#999}.layim-list-friend,.layim-list-group{background-color:#fff}.layui-layim-list li{position:relative;height:42px;padding:5px 15px 5px 60px;font-size:0}.layui-layim-list li:active{background-color:#F2F2F2;background-color:rgba(0,0,0,.05)}.layui-layim-list li.layim-null{height:20px;line-height:20px;padding:10px 0;color:#999;text-align:center;cursor:default;font-size:14px}.layim-list-history li.layim-null{padding:30px 0;border-bottom:none;background-color:#eee}.layui-layim-list li *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:17px}.layui-layim-list li span{margin-top:2px;max-width:155px;font-size:17px}.layui-layim-list li img{position:absolute;left:12px;top:8px;width:36px;height:36px;border-radius:100%}.layui-layim-list li p{display:block;padding-right:30px;line-height:18px;font-size:13px;color:#999}.layui-layim-list li .layim-msg-status{display:none;position:absolute;right:10px;bottom:7px;padding:0 5px;height:17px;line-height:17px;border-radius:17px;text-align:center;font-size:10px;background-color:#F74C31;color:#fff}.layim-list-gray{-webkit-filter:grayscale(100%);-ms-filter:grayscale(100%);filter:grayscale(100%);filter:gray}.layim-list-top{background-color:#fff;font-size:17px}.layim-list-top li{position:relative;padding:0 15px 0 50px;line-height:45px;border-bottom:1px solid #f2f2f2;cursor:pointer}.layim-list-top li:last-child{margin-bottom:10px;border-bottom:none}.layim-list-top li .layui-icon{position:absolute;left:12px;top:0;margin-right:10px;color:#36373C;font-size:24px}.layim-list-top li[layim-event=newFriend] .layui-icon{left:15px}.layim-panel,.layim-title{position:fixed;left:0;right:0;top:0}.layim-list-top li[layim-event=group] .layui-icon{font-size:20px}.layim-list-top li[layim-event=about] .layui-icon{font-size:25px}.layim-panel{bottom:0;background-color:#eee;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}.layim-title{height:50px;line-height:50px;padding:0 15px;background-color:#36373C;color:#fff;font-size:18px}.layim-chat-status{padding-left:15px;font-size:14px;opacity:.7}.layim-title .layim-chat-back{display:inline-block;vertical-align:middle;position:relative;padding:0 15px;margin-left:-10px;top:0;font-size:24px;cursor:pointer}.layim-chat-detail{position:absolute;right:0;top:0;padding:0 15px;font-size:18px;cursor:pointer}.layim-chat-main,.layim-content{position:fixed;top:50px;left:0;right:0;overflow-y:auto;overflow-x:hidden}.layim-chat-detail:active,.layim-title .layim-chat-back:active{opacity:.8}.layui-layim .layim-title{text-align:left}.layui-layim .layim-title p{padding:0 15px}.layim-content{bottom:0}.layim-chat-main{width:100%;bottom:85px;padding:15px;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layim-chat-main ul{overflow-x:hidden}.layim-chat-main ul li{position:relative;font-size:0;margin-bottom:10px;padding-left:60px;min-height:68px}.layim-chat-text,.layim-chat-user{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:15px}.layim-chat-user{position:absolute;left:3px}.layim-chat-user img{width:40px;height:40px;border-radius:100%}.layim-chat-user cite{position:absolute;left:60px;top:-2px;width:500px;line-height:24px;font-size:12px;white-space:nowrap;color:#999;text-align:left;font-style:normal}.layim-chat-user cite i{padding-left:15px;font-style:normal}.layim-chat-text{position:relative;min-height:22px;line-height:22px;margin-top:25px;padding:8px 15px;background-color:#fff;border-radius:3px;color:#333;word-break:break-all}.layim-chat-text:after{content:'';position:absolute;left:-10px;top:13px;width:0;height:0;border-style:solid dashed dashed;border-color:#fff transparent transparent;overflow:hidden;border-width:10px}.layim-chat-text a{color:#33DF83}.layim-chat-text img{max-width:100%;vertical-align:middle}.layim-chat-text .layui-layim-file,.layui-layim-file{display:block;text-align:center}.layim-chat-text .layui-layim-file{color:#333}.layui-layim-file:active{opacity:.9}.layui-layim-file i{font-size:80px;line-height:80px}.layui-layim-file cite{display:block;line-height:20px;font-size:17px}.layui-layim-audio{text-align:center;cursor:pointer}.layui-layim-audio .layui-icon{position:relative;top:5px;font-size:24px}.layui-layim-audio p{margin-top:3px}.layui-layim-video{width:120px;height:80px;line-height:80px;background-color:#333;text-align:center;border-radius:3px}.layui-layim-video .layui-icon{font-size:36px;cursor:pointer;color:#fff}.layim-chat-main ul .layim-chat-mine{text-align:right;padding-left:0;padding-right:60px}.layim-chat-mine .layim-chat-user{left:auto;right:3px}.layim-chat-mine .layim-chat-user cite{left:auto;right:60px;text-align:right}.layim-chat-mine .layim-chat-user cite i{padding-left:0;padding-right:15px}.layim-chat-mine .layim-chat-text{margin-left:0;text-align:left;background-color:#5FB878;color:#fff}.layim-chat-mine .layim-chat-text:after{left:auto;right:-10px;border-top-color:#5FB878}.layim-chat-mine .layim-chat-text a{color:#fff}.layim-chat-main ul .layim-chat-system{min-height:0;margin:20px 0 5px;padding:0}.layim-chat-system{margin:10px 0;text-align:center}.layim-chat-system span{display:inline-block;line-height:30px;padding:0 15px;border-radius:3px;background-color:#ddd;color:#fff;font-size:14px;cursor:pointer}.layim-chat-footer{position:fixed;bottom:0;left:10px;right:10px;height:80px}.layim-chat-send{display:-webkit-box;display:-webkit-flex;display:flex}.layim-chat-send input{-webkit-box-flex:1;-webkit-flex:1;flex:1;height:40px;padding-left:5px;border:0;background-color:#fff;border-radius:3px}.layim-chat-send button{border-radius:3px;height:40px;padding:0 20px;border:0;margin-left:10px;background-color:#5FB878;color:#fff}.layim-chat-tool{position:relative;width:100%;overflow-x:auto;padding:0;height:38px;line-height:38px;margin-top:3px;font-size:0;white-space:nowrap}.layim-chat-tool span{position:relative;margin:0 15px;display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:28px;cursor:pointer}.layim-chat-tool .layim-tool-log{position:absolute;right:5px;font-size:14px}.layim-tool-log i{position:relative;top:2px;margin-right:5px;font-size:20px;color:#999}.layim-tool-image input{position:absolute;font-size:0;left:0;top:0;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layim-layer{position:fixed;bottom:85px;left:10px;right:10px;margin:0 auto}.layui-layim-face{position:relative;max-height:180px;overflow:auto;padding:10px;font-size:0}.layui-layim-face li{cursor:pointer;display:inline-block;vertical-align:bottom;padding:5px 2px;text-align:center;width:10%;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-layim-face li img{width:22px;height:22px}.layim-about{font-size:17px}.layim-about .layui-m-layercont{text-align:left}.layim-about .layui-m-layercont p{line-height:30px}.layim-about .layui-m-layercont a{color:#01AAED}
\ No newline at end of file
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/1.jpg b/src/main/resources/static/layui/css/modules/layim/skin/1.jpg
new file mode 100644
index 0000000..d9f9926
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/1.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/2.jpg b/src/main/resources/static/layui/css/modules/layim/skin/2.jpg
new file mode 100644
index 0000000..0bffb50
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/2.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/3.jpg b/src/main/resources/static/layui/css/modules/layim/skin/3.jpg
new file mode 100644
index 0000000..53ba921
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/3.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/4.jpg b/src/main/resources/static/layui/css/modules/layim/skin/4.jpg
new file mode 100644
index 0000000..83b4738
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/4.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/5.jpg b/src/main/resources/static/layui/css/modules/layim/skin/5.jpg
new file mode 100644
index 0000000..8ed74b9
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/5.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/skin/logo.jpg b/src/main/resources/static/layui/css/modules/layim/skin/logo.jpg
new file mode 100644
index 0000000..26c7358
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/skin/logo.jpg differ
diff --git a/src/main/resources/static/layui/css/modules/layim/voice/default.mp3 b/src/main/resources/static/layui/css/modules/layim/voice/default.mp3
new file mode 100644
index 0000000..90013c5
Binary files /dev/null and b/src/main/resources/static/layui/css/modules/layim/voice/default.mp3 differ
diff --git a/src/main/resources/static/layui/font/iconfont.eot b/src/main/resources/static/layui/font/iconfont.eot
new file mode 100644
index 0000000..93b3d5a
Binary files /dev/null and b/src/main/resources/static/layui/font/iconfont.eot differ
diff --git a/src/main/resources/static/layui/font/iconfont.svg b/src/main/resources/static/layui/font/iconfont.svg
new file mode 100644
index 0000000..1c7ffe9
--- /dev/null
+++ b/src/main/resources/static/layui/font/iconfont.svg
@@ -0,0 +1,473 @@
+
+
+
+
+
+Created by iconfont
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/static/layui/font/iconfont.ttf b/src/main/resources/static/layui/font/iconfont.ttf
new file mode 100644
index 0000000..0c8b0a5
Binary files /dev/null and b/src/main/resources/static/layui/font/iconfont.ttf differ
diff --git a/src/main/resources/static/layui/font/iconfont.woff b/src/main/resources/static/layui/font/iconfont.woff
new file mode 100644
index 0000000..786bb2a
Binary files /dev/null and b/src/main/resources/static/layui/font/iconfont.woff differ
diff --git a/src/main/resources/static/layui/images/face/0.gif b/src/main/resources/static/layui/images/face/0.gif
new file mode 100644
index 0000000..a63f0d5
Binary files /dev/null and b/src/main/resources/static/layui/images/face/0.gif differ
diff --git a/src/main/resources/static/layui/images/face/1.gif b/src/main/resources/static/layui/images/face/1.gif
new file mode 100644
index 0000000..b2b78b2
Binary files /dev/null and b/src/main/resources/static/layui/images/face/1.gif differ
diff --git a/src/main/resources/static/layui/images/face/10.gif b/src/main/resources/static/layui/images/face/10.gif
new file mode 100644
index 0000000..556c7e3
Binary files /dev/null and b/src/main/resources/static/layui/images/face/10.gif differ
diff --git a/src/main/resources/static/layui/images/face/11.gif b/src/main/resources/static/layui/images/face/11.gif
new file mode 100644
index 0000000..2bfc58b
Binary files /dev/null and b/src/main/resources/static/layui/images/face/11.gif differ
diff --git a/src/main/resources/static/layui/images/face/12.gif b/src/main/resources/static/layui/images/face/12.gif
new file mode 100644
index 0000000..1c321c7
Binary files /dev/null and b/src/main/resources/static/layui/images/face/12.gif differ
diff --git a/src/main/resources/static/layui/images/face/13.gif b/src/main/resources/static/layui/images/face/13.gif
new file mode 100644
index 0000000..300bbc2
Binary files /dev/null and b/src/main/resources/static/layui/images/face/13.gif differ
diff --git a/src/main/resources/static/layui/images/face/14.gif b/src/main/resources/static/layui/images/face/14.gif
new file mode 100644
index 0000000..43b6d0a
Binary files /dev/null and b/src/main/resources/static/layui/images/face/14.gif differ
diff --git a/src/main/resources/static/layui/images/face/15.gif b/src/main/resources/static/layui/images/face/15.gif
new file mode 100644
index 0000000..c9f25fa
Binary files /dev/null and b/src/main/resources/static/layui/images/face/15.gif differ
diff --git a/src/main/resources/static/layui/images/face/16.gif b/src/main/resources/static/layui/images/face/16.gif
new file mode 100644
index 0000000..34f28e4
Binary files /dev/null and b/src/main/resources/static/layui/images/face/16.gif differ
diff --git a/src/main/resources/static/layui/images/face/17.gif b/src/main/resources/static/layui/images/face/17.gif
new file mode 100644
index 0000000..39cd035
Binary files /dev/null and b/src/main/resources/static/layui/images/face/17.gif differ
diff --git a/src/main/resources/static/layui/images/face/18.gif b/src/main/resources/static/layui/images/face/18.gif
new file mode 100644
index 0000000..7bce299
Binary files /dev/null and b/src/main/resources/static/layui/images/face/18.gif differ
diff --git a/src/main/resources/static/layui/images/face/19.gif b/src/main/resources/static/layui/images/face/19.gif
new file mode 100644
index 0000000..adac542
Binary files /dev/null and b/src/main/resources/static/layui/images/face/19.gif differ
diff --git a/src/main/resources/static/layui/images/face/2.gif b/src/main/resources/static/layui/images/face/2.gif
new file mode 100644
index 0000000..7edbb58
Binary files /dev/null and b/src/main/resources/static/layui/images/face/2.gif differ
diff --git a/src/main/resources/static/layui/images/face/20.gif b/src/main/resources/static/layui/images/face/20.gif
new file mode 100644
index 0000000..50631a6
Binary files /dev/null and b/src/main/resources/static/layui/images/face/20.gif differ
diff --git a/src/main/resources/static/layui/images/face/21.gif b/src/main/resources/static/layui/images/face/21.gif
new file mode 100644
index 0000000..b984212
Binary files /dev/null and b/src/main/resources/static/layui/images/face/21.gif differ
diff --git a/src/main/resources/static/layui/images/face/22.gif b/src/main/resources/static/layui/images/face/22.gif
new file mode 100644
index 0000000..1f0bd8b
Binary files /dev/null and b/src/main/resources/static/layui/images/face/22.gif differ
diff --git a/src/main/resources/static/layui/images/face/23.gif b/src/main/resources/static/layui/images/face/23.gif
new file mode 100644
index 0000000..e05e0f9
Binary files /dev/null and b/src/main/resources/static/layui/images/face/23.gif differ
diff --git a/src/main/resources/static/layui/images/face/24.gif b/src/main/resources/static/layui/images/face/24.gif
new file mode 100644
index 0000000..f35928a
Binary files /dev/null and b/src/main/resources/static/layui/images/face/24.gif differ
diff --git a/src/main/resources/static/layui/images/face/25.gif b/src/main/resources/static/layui/images/face/25.gif
new file mode 100644
index 0000000..0b4a883
Binary files /dev/null and b/src/main/resources/static/layui/images/face/25.gif differ
diff --git a/src/main/resources/static/layui/images/face/26.gif b/src/main/resources/static/layui/images/face/26.gif
new file mode 100644
index 0000000..45c4fb5
Binary files /dev/null and b/src/main/resources/static/layui/images/face/26.gif differ
diff --git a/src/main/resources/static/layui/images/face/27.gif b/src/main/resources/static/layui/images/face/27.gif
new file mode 100644
index 0000000..7a4c013
Binary files /dev/null and b/src/main/resources/static/layui/images/face/27.gif differ
diff --git a/src/main/resources/static/layui/images/face/28.gif b/src/main/resources/static/layui/images/face/28.gif
new file mode 100644
index 0000000..fc5a0cf
Binary files /dev/null and b/src/main/resources/static/layui/images/face/28.gif differ
diff --git a/src/main/resources/static/layui/images/face/29.gif b/src/main/resources/static/layui/images/face/29.gif
new file mode 100644
index 0000000..5dd7442
Binary files /dev/null and b/src/main/resources/static/layui/images/face/29.gif differ
diff --git a/src/main/resources/static/layui/images/face/3.gif b/src/main/resources/static/layui/images/face/3.gif
new file mode 100644
index 0000000..86df67b
Binary files /dev/null and b/src/main/resources/static/layui/images/face/3.gif differ
diff --git a/src/main/resources/static/layui/images/face/30.gif b/src/main/resources/static/layui/images/face/30.gif
new file mode 100644
index 0000000..b751f98
Binary files /dev/null and b/src/main/resources/static/layui/images/face/30.gif differ
diff --git a/src/main/resources/static/layui/images/face/31.gif b/src/main/resources/static/layui/images/face/31.gif
new file mode 100644
index 0000000..c9476d7
Binary files /dev/null and b/src/main/resources/static/layui/images/face/31.gif differ
diff --git a/src/main/resources/static/layui/images/face/32.gif b/src/main/resources/static/layui/images/face/32.gif
new file mode 100644
index 0000000..9931b06
Binary files /dev/null and b/src/main/resources/static/layui/images/face/32.gif differ
diff --git a/src/main/resources/static/layui/images/face/33.gif b/src/main/resources/static/layui/images/face/33.gif
new file mode 100644
index 0000000..59111a3
Binary files /dev/null and b/src/main/resources/static/layui/images/face/33.gif differ
diff --git a/src/main/resources/static/layui/images/face/34.gif b/src/main/resources/static/layui/images/face/34.gif
new file mode 100644
index 0000000..a334548
Binary files /dev/null and b/src/main/resources/static/layui/images/face/34.gif differ
diff --git a/src/main/resources/static/layui/images/face/35.gif b/src/main/resources/static/layui/images/face/35.gif
new file mode 100644
index 0000000..a932264
Binary files /dev/null and b/src/main/resources/static/layui/images/face/35.gif differ
diff --git a/src/main/resources/static/layui/images/face/36.gif b/src/main/resources/static/layui/images/face/36.gif
new file mode 100644
index 0000000..6de432a
Binary files /dev/null and b/src/main/resources/static/layui/images/face/36.gif differ
diff --git a/src/main/resources/static/layui/images/face/37.gif b/src/main/resources/static/layui/images/face/37.gif
new file mode 100644
index 0000000..d05f2da
Binary files /dev/null and b/src/main/resources/static/layui/images/face/37.gif differ
diff --git a/src/main/resources/static/layui/images/face/38.gif b/src/main/resources/static/layui/images/face/38.gif
new file mode 100644
index 0000000..8b1c88a
Binary files /dev/null and b/src/main/resources/static/layui/images/face/38.gif differ
diff --git a/src/main/resources/static/layui/images/face/39.gif b/src/main/resources/static/layui/images/face/39.gif
new file mode 100644
index 0000000..38b84a5
Binary files /dev/null and b/src/main/resources/static/layui/images/face/39.gif differ
diff --git a/src/main/resources/static/layui/images/face/4.gif b/src/main/resources/static/layui/images/face/4.gif
new file mode 100644
index 0000000..d52200c
Binary files /dev/null and b/src/main/resources/static/layui/images/face/4.gif differ
diff --git a/src/main/resources/static/layui/images/face/40.gif b/src/main/resources/static/layui/images/face/40.gif
new file mode 100644
index 0000000..ae42991
Binary files /dev/null and b/src/main/resources/static/layui/images/face/40.gif differ
diff --git a/src/main/resources/static/layui/images/face/41.gif b/src/main/resources/static/layui/images/face/41.gif
new file mode 100644
index 0000000..b9c715c
Binary files /dev/null and b/src/main/resources/static/layui/images/face/41.gif differ
diff --git a/src/main/resources/static/layui/images/face/42.gif b/src/main/resources/static/layui/images/face/42.gif
new file mode 100644
index 0000000..0eb1434
Binary files /dev/null and b/src/main/resources/static/layui/images/face/42.gif differ
diff --git a/src/main/resources/static/layui/images/face/43.gif b/src/main/resources/static/layui/images/face/43.gif
new file mode 100644
index 0000000..ac0b700
Binary files /dev/null and b/src/main/resources/static/layui/images/face/43.gif differ
diff --git a/src/main/resources/static/layui/images/face/44.gif b/src/main/resources/static/layui/images/face/44.gif
new file mode 100644
index 0000000..ad44497
Binary files /dev/null and b/src/main/resources/static/layui/images/face/44.gif differ
diff --git a/src/main/resources/static/layui/images/face/45.gif b/src/main/resources/static/layui/images/face/45.gif
new file mode 100644
index 0000000..6837fca
Binary files /dev/null and b/src/main/resources/static/layui/images/face/45.gif differ
diff --git a/src/main/resources/static/layui/images/face/46.gif b/src/main/resources/static/layui/images/face/46.gif
new file mode 100644
index 0000000..d62916d
Binary files /dev/null and b/src/main/resources/static/layui/images/face/46.gif differ
diff --git a/src/main/resources/static/layui/images/face/47.gif b/src/main/resources/static/layui/images/face/47.gif
new file mode 100644
index 0000000..58a0836
Binary files /dev/null and b/src/main/resources/static/layui/images/face/47.gif differ
diff --git a/src/main/resources/static/layui/images/face/48.gif b/src/main/resources/static/layui/images/face/48.gif
new file mode 100644
index 0000000..7ffd161
Binary files /dev/null and b/src/main/resources/static/layui/images/face/48.gif differ
diff --git a/src/main/resources/static/layui/images/face/49.gif b/src/main/resources/static/layui/images/face/49.gif
new file mode 100644
index 0000000..959b992
Binary files /dev/null and b/src/main/resources/static/layui/images/face/49.gif differ
diff --git a/src/main/resources/static/layui/images/face/5.gif b/src/main/resources/static/layui/images/face/5.gif
new file mode 100644
index 0000000..4e8b09f
Binary files /dev/null and b/src/main/resources/static/layui/images/face/5.gif differ
diff --git a/src/main/resources/static/layui/images/face/50.gif b/src/main/resources/static/layui/images/face/50.gif
new file mode 100644
index 0000000..6e22e7f
Binary files /dev/null and b/src/main/resources/static/layui/images/face/50.gif differ
diff --git a/src/main/resources/static/layui/images/face/51.gif b/src/main/resources/static/layui/images/face/51.gif
new file mode 100644
index 0000000..ad3f4d3
Binary files /dev/null and b/src/main/resources/static/layui/images/face/51.gif differ
diff --git a/src/main/resources/static/layui/images/face/52.gif b/src/main/resources/static/layui/images/face/52.gif
new file mode 100644
index 0000000..39f8a22
Binary files /dev/null and b/src/main/resources/static/layui/images/face/52.gif differ
diff --git a/src/main/resources/static/layui/images/face/53.gif b/src/main/resources/static/layui/images/face/53.gif
new file mode 100644
index 0000000..a181ee7
Binary files /dev/null and b/src/main/resources/static/layui/images/face/53.gif differ
diff --git a/src/main/resources/static/layui/images/face/54.gif b/src/main/resources/static/layui/images/face/54.gif
new file mode 100644
index 0000000..e289d92
Binary files /dev/null and b/src/main/resources/static/layui/images/face/54.gif differ
diff --git a/src/main/resources/static/layui/images/face/55.gif b/src/main/resources/static/layui/images/face/55.gif
new file mode 100644
index 0000000..4351083
Binary files /dev/null and b/src/main/resources/static/layui/images/face/55.gif differ
diff --git a/src/main/resources/static/layui/images/face/56.gif b/src/main/resources/static/layui/images/face/56.gif
new file mode 100644
index 0000000..e0eff22
Binary files /dev/null and b/src/main/resources/static/layui/images/face/56.gif differ
diff --git a/src/main/resources/static/layui/images/face/57.gif b/src/main/resources/static/layui/images/face/57.gif
new file mode 100644
index 0000000..0bf130f
Binary files /dev/null and b/src/main/resources/static/layui/images/face/57.gif differ
diff --git a/src/main/resources/static/layui/images/face/58.gif b/src/main/resources/static/layui/images/face/58.gif
new file mode 100644
index 0000000..0f06508
Binary files /dev/null and b/src/main/resources/static/layui/images/face/58.gif differ
diff --git a/src/main/resources/static/layui/images/face/59.gif b/src/main/resources/static/layui/images/face/59.gif
new file mode 100644
index 0000000..7081e4f
Binary files /dev/null and b/src/main/resources/static/layui/images/face/59.gif differ
diff --git a/src/main/resources/static/layui/images/face/6.gif b/src/main/resources/static/layui/images/face/6.gif
new file mode 100644
index 0000000..f7715bf
Binary files /dev/null and b/src/main/resources/static/layui/images/face/6.gif differ
diff --git a/src/main/resources/static/layui/images/face/60.gif b/src/main/resources/static/layui/images/face/60.gif
new file mode 100644
index 0000000..6e15f89
Binary files /dev/null and b/src/main/resources/static/layui/images/face/60.gif differ
diff --git a/src/main/resources/static/layui/images/face/61.gif b/src/main/resources/static/layui/images/face/61.gif
new file mode 100644
index 0000000..f092d7e
Binary files /dev/null and b/src/main/resources/static/layui/images/face/61.gif differ
diff --git a/src/main/resources/static/layui/images/face/62.gif b/src/main/resources/static/layui/images/face/62.gif
new file mode 100644
index 0000000..7fe4984
Binary files /dev/null and b/src/main/resources/static/layui/images/face/62.gif differ
diff --git a/src/main/resources/static/layui/images/face/63.gif b/src/main/resources/static/layui/images/face/63.gif
new file mode 100644
index 0000000..cf8e23e
Binary files /dev/null and b/src/main/resources/static/layui/images/face/63.gif differ
diff --git a/src/main/resources/static/layui/images/face/64.gif b/src/main/resources/static/layui/images/face/64.gif
new file mode 100644
index 0000000..a779719
Binary files /dev/null and b/src/main/resources/static/layui/images/face/64.gif differ
diff --git a/src/main/resources/static/layui/images/face/65.gif b/src/main/resources/static/layui/images/face/65.gif
new file mode 100644
index 0000000..7bb98f2
Binary files /dev/null and b/src/main/resources/static/layui/images/face/65.gif differ
diff --git a/src/main/resources/static/layui/images/face/66.gif b/src/main/resources/static/layui/images/face/66.gif
new file mode 100644
index 0000000..bb6d077
Binary files /dev/null and b/src/main/resources/static/layui/images/face/66.gif differ
diff --git a/src/main/resources/static/layui/images/face/67.gif b/src/main/resources/static/layui/images/face/67.gif
new file mode 100644
index 0000000..6e33f7c
Binary files /dev/null and b/src/main/resources/static/layui/images/face/67.gif differ
diff --git a/src/main/resources/static/layui/images/face/68.gif b/src/main/resources/static/layui/images/face/68.gif
new file mode 100644
index 0000000..1a6c400
Binary files /dev/null and b/src/main/resources/static/layui/images/face/68.gif differ
diff --git a/src/main/resources/static/layui/images/face/69.gif b/src/main/resources/static/layui/images/face/69.gif
new file mode 100644
index 0000000..a02f0b2
Binary files /dev/null and b/src/main/resources/static/layui/images/face/69.gif differ
diff --git a/src/main/resources/static/layui/images/face/7.gif b/src/main/resources/static/layui/images/face/7.gif
new file mode 100644
index 0000000..e6d4db8
Binary files /dev/null and b/src/main/resources/static/layui/images/face/7.gif differ
diff --git a/src/main/resources/static/layui/images/face/70.gif b/src/main/resources/static/layui/images/face/70.gif
new file mode 100644
index 0000000..416c5c1
Binary files /dev/null and b/src/main/resources/static/layui/images/face/70.gif differ
diff --git a/src/main/resources/static/layui/images/face/71.gif b/src/main/resources/static/layui/images/face/71.gif
new file mode 100644
index 0000000..c17d60c
Binary files /dev/null and b/src/main/resources/static/layui/images/face/71.gif differ
diff --git a/src/main/resources/static/layui/images/face/8.gif b/src/main/resources/static/layui/images/face/8.gif
new file mode 100644
index 0000000..66f967b
Binary files /dev/null and b/src/main/resources/static/layui/images/face/8.gif differ
diff --git a/src/main/resources/static/layui/images/face/9.gif b/src/main/resources/static/layui/images/face/9.gif
new file mode 100644
index 0000000..6044740
Binary files /dev/null and b/src/main/resources/static/layui/images/face/9.gif differ
diff --git a/src/main/resources/static/layui/lay/modules/carousel.js b/src/main/resources/static/layui/lay/modules/carousel.js
new file mode 100644
index 0000000..2be2c8c
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/carousel.js
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i([''+("updown"===n.anim?"":"")+" ",''+("updown"===n.anim?"":"")+" "].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['',function(){var i=[];return layui.each(e.elemItem,function(e){i.push(" ")}),i.join("")}()," "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a/g,">").replace(/'/g,"'").replace(/"/g,""")),c.html(''+o.replace(/[\r\t\n]+/g," ")+" "),c.find(">.layui-code-h3")[0]||c.prepend(''+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code ':"")+" ");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss");
\ No newline at end of file
diff --git a/src/main/resources/static/layui/lay/modules/colorpicker.js b/src/main/resources/static/layui/lay/modules/colorpicker.js
new file mode 100644
index 0000000..fd99bf8
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/colorpicker.js
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(e){"use strict";var i=layui.jquery,o={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var o=this;return o.config=i.extend({},o.config,e),o},on:function(e,i){return layui.onevent.call(this,"colorpicker",e,i)}},r=function(){var e=this,i=e.config;return{config:i}},t="colorpicker",n="layui-show",l="layui-colorpicker",c=".layui-colorpicker-main",a="layui-icon-down",s="layui-icon-close",f="layui-colorpicker-trigger-span",d="layui-colorpicker-trigger-i",u="layui-colorpicker-side",p="layui-colorpicker-side-slider",g="layui-colorpicker-basis",v="layui-colorpicker-alpha-bgcolor",h="layui-colorpicker-alpha-slider",m="layui-colorpicker-basis-cursor",b="layui-colorpicker-main-input",k=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!=r?255*t/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},y=function(e){var e=e.indexOf("#")>-1?e.substring(1):e;if(3==e.length){var i=e.split("");e=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]}e=parseInt(e,16);var o={r:e>>16,g:(65280&e)>>8,b:255&e};return k(o)},x=function(e){var i={},o=e.h,r=255*e.s/100,t=255*e.b/100;if(0==r)i.r=i.g=i.b=t;else{var n=t,l=(255-r)*t/255,c=(n-l)*(o%60)/60;360==o&&(o=0),o<60?(i.r=n,i.b=l,i.g=l+c):o<120?(i.g=n,i.b=l,i.r=n-c):o<180?(i.g=n,i.r=l,i.b=l+c):o<240?(i.b=n,i.r=l,i.g=n-c):o<300?(i.b=n,i.g=l,i.r=l+c):o<360?(i.r=n,i.g=l,i.b=n-c):(i.r=0,i.g=0,i.b=0)}return{r:Math.round(i.r),g:Math.round(i.g),b:Math.round(i.b)}},C=function(e){var o=x(e),r=[o.r.toString(16),o.g.toString(16),o.b.toString(16)];return i.each(r,function(e,i){1==i.length&&(r[e]="0"+i)}),r.join("")},P=function(e){var i=/[0-9]{1,3}/g,o=e.match(i)||[];return{r:o[0],g:o[1],b:o[2]}},B=i(window),w=i(document),D=function(e){var r=this;r.index=++o.index,r.config=i.extend({},r.config,o.config,e),r.render()};D.prototype.config={color:"",size:null,alpha:!1,format:"hex",predefine:!1,colors:["#009688","#5FB878","#1E9FFF","#FF5722","#FFB800","#01AAED","#999","#c00","#ff8c00","#ffd700","#90ee90","#00ced1","#1e90ff","#c71585","rgb(0, 186, 189)","rgb(255, 120, 0)","rgb(250, 212, 0)","#393D49","rgba(0,0,0,.5)","rgba(255, 69, 0, 0.68)","rgba(144, 240, 144, 0.5)","rgba(31, 147, 255, 0.73)"]},D.prototype.render=function(){var e=this,o=e.config,r=i(['',"",'3&&(o.alpha&&"rgb"==o.format||(e="#"+C(k(P(o.color))))),"background: "+e):e}()+'">',' '," "," ","
"].join("")),t=i(o.elem);o.size&&r.addClass("layui-colorpicker-"+o.size),t.addClass("layui-inline").html(e.elemColorBox=r),e.color=e.elemColorBox.find("."+f)[0].style.background,e.events()},D.prototype.renderPicker=function(){var e=this,o=e.config,r=e.elemColorBox[0],t=e.elemPicker=i(['','
",'
",function(){if(o.predefine){var e=['
'];return layui.each(o.colors,function(i,o){e.push(['
"].join(""))}),e.push("
"),e.join("")}return""}(),'
','
',' ',"
",'
','清空 ','确定 ',"
","
"].join(""));e.elemColorBox.find("."+f)[0];i(c)[0]&&i(c).data("index")==e.index?e.removePicker(D.thisElemInd):(e.removePicker(D.thisElemInd),i("body").append(t)),D.thisElemInd=e.index,D.thisColor=r.style.background,e.position(),e.pickerEvents()},D.prototype.removePicker=function(e){var o=this;o.config;return i("#layui-colorpicker"+(e||o.index)).remove(),o},D.prototype.position=function(){var e=this,i=e.config,o=e.bindElem||e.elemColorBox[0],r=e.elemPicker[0],t=o.getBoundingClientRect(),n=r.offsetWidth,l=r.offsetHeight,c=function(e){return e=e?"scrollLeft":"scrollTop",document.body[e]|document.documentElement[e]},a=function(e){return document.documentElement[e?"clientWidth":"clientHeight"]},s=5,f=t.left,d=t.bottom;f-=(n-o.offsetWidth)/2,d+=s,f+n+s>a("width")?f=a("width")-n-s:f
a()&&(d=t.top>l?t.top-l:a()-l,d-=2*s),i.position&&(r.style.position=i.position),r.style.left=f+("fixed"===i.position?0:c(1))+"px",r.style.top=d+("fixed"===i.position?0:c())+"px"},D.prototype.val=function(){var e=this,i=(e.config,e.elemColorBox.find("."+f)),o=e.elemPicker.find("."+b),r=i[0],t=r.style.backgroundColor;if(t){var n=k(P(t)),l=i.attr("lay-type");if(e.select(n.h,n.s,n.b),"torgb"===l&&o.find("input").val(t),"rgba"===l){var c=P(t);if(3==(t.match(/[0-9]{1,3}/g)||[]).length)o.find("input").val("rgba("+c.r+", "+c.g+", "+c.b+", 1)"),e.elemPicker.find("."+h).css("left",280);else{o.find("input").val(t);var a=280*t.slice(t.lastIndexOf(",")+1,t.length-1);e.elemPicker.find("."+h).css("left",a)}e.elemPicker.find("."+v)[0].style.background="linear-gradient(to right, rgba("+c.r+", "+c.g+", "+c.b+", 0), rgb("+c.r+", "+c.g+", "+c.b+"))"}}else e.select(0,100,100),o.find("input").val(""),e.elemPicker.find("."+v)[0].style.background="",e.elemPicker.find("."+h).css("left",280)},D.prototype.side=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=r.attr("lay-type"),n=e.elemPicker.find("."+u),l=e.elemPicker.find("."+p),c=e.elemPicker.find("."+g),y=e.elemPicker.find("."+m),C=e.elemPicker.find("."+v),w=e.elemPicker.find("."+h),D=l[0].offsetTop/180*360,E=100-(y[0].offsetTop+3)/180*100,H=(y[0].offsetLeft+3)/260*100,W=Math.round(w[0].offsetLeft/280*100)/100,j=e.elemColorBox.find("."+d),F=e.elemPicker.find(".layui-colorpicker-pre").children("div"),L=function(i,n,l,c){e.select(i,n,l);var f=x({h:i,s:n,b:l});if(j.addClass(a).removeClass(s),r[0].style.background="rgb("+f.r+", "+f.g+", "+f.b+")","torgb"===t&&e.elemPicker.find("."+b).find("input").val("rgb("+f.r+", "+f.g+", "+f.b+")"),"rgba"===t){var d=0;d=280*c,w.css("left",d),e.elemPicker.find("."+b).find("input").val("rgba("+f.r+", "+f.g+", "+f.b+", "+c+")"),r[0].style.background="rgba("+f.r+", "+f.g+", "+f.b+", "+c+")",C[0].style.background="linear-gradient(to right, rgba("+f.r+", "+f.g+", "+f.b+", 0), rgb("+f.r+", "+f.g+", "+f.b+"))"}o.change&&o.change(e.elemPicker.find("."+b).find("input").val())},M=i(['
t&&(r=t);var l=r/180*360;D=l,L(l,H,E,W),e.preventDefault()};Y(r),e.preventDefault()}),n.on("click",function(e){var o=e.clientY-i(this).offset().top;o<0&&(o=0),o>this.offsetHeight&&(o=this.offsetHeight);var r=o/180*360;D=r,L(r,H,E,W),e.preventDefault()}),y.on("mousedown",function(e){var i=this.offsetTop,o=this.offsetLeft,r=e.clientY,t=e.clientX,n=function(e){var n=i+(e.clientY-r),l=o+(e.clientX-t),a=c[0].offsetHeight-3,s=c[0].offsetWidth-3;n<-3&&(n=-3),n>a&&(n=a),l<-3&&(l=-3),l>s&&(l=s);var f=(l+3)/260*100,d=100-(n+3)/180*100;E=d,H=f,L(D,f,d,W),e.preventDefault()};layui.stope(e),Y(n),e.preventDefault()}),c.on("mousedown",function(e){var o=e.clientY-i(this).offset().top-3+B.scrollTop(),r=e.clientX-i(this).offset().left-3+B.scrollLeft();o<-3&&(o=-3),o>this.offsetHeight-3&&(o=this.offsetHeight-3),r<-3&&(r=-3),r>this.offsetWidth-3&&(r=this.offsetWidth-3);var t=(r+3)/260*100,n=100-(o+3)/180*100;E=n,H=t,L(D,t,n,W),e.preventDefault(),y.trigger(e,"mousedown")}),w.on("mousedown",function(e){var i=this.offsetLeft,o=e.clientX,r=function(e){var r=i+(e.clientX-o),t=C[0].offsetWidth;r<0&&(r=0),r>t&&(r=t);var n=Math.round(r/280*100)/100;W=n,L(D,H,E,n),e.preventDefault()};Y(r),e.preventDefault()}),C.on("click",function(e){var o=e.clientX-i(this).offset().left;o<0&&(o=0),o>this.offsetWidth&&(o=this.offsetWidth);var r=Math.round(o/280*100)/100;W=r,L(D,H,E,r),e.preventDefault()}),F.each(function(){i(this).on("click",function(){i(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e,o=this.style.backgroundColor,r=k(P(o)),t=o.slice(o.lastIndexOf(",")+1,o.length-1);D=r.h,H=r.s,E=r.b,3==(o.match(/[0-9]{1,3}/g)||[]).length&&(t=1),W=t,e=280*t,L(r.h,r.s,r.b,t)})})},D.prototype.select=function(e,i,o,r){var t=this,n=(t.config,C({h:e,s:100,b:100})),l=C({h:e,s:i,b:o}),c=e/360*180,a=180-o/100*180-3,s=i/100*260-3;t.elemPicker.find("."+p).css("top",c),t.elemPicker.find("."+g)[0].style.background="#"+n,t.elemPicker.find("."+m).css({top:a,left:s}),"change"!==r&&t.elemPicker.find("."+b).find("input").val("#"+l)},D.prototype.pickerEvents=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=e.elemPicker.find("."+b+" input"),n={clear:function(i){r[0].style.background="",e.elemColorBox.find("."+d).removeClass(a).addClass(s),e.color="",o.done&&o.done(""),e.removePicker()},confirm:function(i,n){var l=t.val(),c=l,f={};if(l.indexOf(",")>-1){if(f=k(P(l)),e.select(f.h,f.s,f.b),r[0].style.background=c="#"+C(f),(l.match(/[0-9]{1,3}/g)||[]).length>3&&"rgba"===r.attr("lay-type")){var u=280*l.slice(l.lastIndexOf(",")+1,l.length-1);e.elemPicker.find("."+h).css("left",u),r[0].style.background=l,c=l}}else f=y(l),r[0].style.background=c="#"+C(f),e.elemColorBox.find("."+d).removeClass(s).addClass(a);return"change"===n?(e.select(f.h,f.s,f.b,n),void(o.change&&o.change(c))):(e.color=l,o.done&&o.done(l),void e.removePicker())}};e.elemPicker.on("click","*[colorpicker-events]",function(){var e=i(this),o=e.attr("colorpicker-events");n[o]&&n[o].call(this,e)}),t.on("keyup",function(e){var o=i(this);n.confirm.call(this,o,13===e.keyCode?null:"change")})},D.prototype.events=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f);e.elemColorBox.on("click",function(){e.renderPicker(),i(c)[0]&&(e.val(),e.side())}),o.elem[0]&&!e.elemColorBox[0].eventHandler&&(w.on("click",function(o){if(!i(o.target).hasClass(l)&&!i(o.target).parents("."+l)[0]&&!i(o.target).hasClass(c.replace(/\./g,""))&&!i(o.target).parents(c)[0]&&e.elemPicker){if(e.color){var t=k(P(e.color));e.select(t.h,t.s,t.b)}else e.elemColorBox.find("."+d).removeClass(a).addClass(s);r[0].style.background=e.color||"",e.removePicker()}}),B.on("resize",function(){return!(!e.elemPicker||!i(c)[0])&&void e.position()}),e.elemColorBox[0].eventHandler=!0)},o.render=function(e){var i=new D(e);return r.call(i)},e(t,o)});
\ No newline at end of file
diff --git a/src/main/resources/static/layui/lay/modules/element.js b/src/main/resources/static/layui/lay/modules/element.js
new file mode 100644
index 0000000..ac628df
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/element.js
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(t){"use strict";var a=layui.$,i=(layui.hint(),layui.device()),e="element",l="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.children(".layui-tab-bar"),o=l.children(".layui-tab-content"),r='"+(i.title||"unnaming")+" ";return s[0]?s.before(r):n.append(r),o.append(''+(i.content||"")+"
"),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on("click",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e="layui-progress",l=a("."+e+"[lay-filter="+t+"]"),n=l.find("."+e+"-bar"),s=n.find("."+e+"-text");return n.css("width",i),s.text(i),this};var o=".layui-nav",r="layui-nav-item",c="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",y="layui-nav-more",h="layui-anim layui-anim-upbit",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children("li").index(r),c=o.headerElem?r.parent():r.parents(".layui-tab").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(".layui-tab-content").children(".layui-tab-item"),d=r.find("a"),y=c.attr("lay-filter");"javascript:;"!==d.attr("href")&&"_blank"===d.attr("target")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,"tab("+y+")",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(".layui-tab").eq(0),r=o.children(".layui-tab-content").children(".layui-tab-item"),c=o.attr("lay-filter");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,"tabDelete("+c+")",{elem:o,index:s})},tabAuto:function(){var t="layui-tab-more",e="layui-tab-bar",l="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),r=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),c=a(' ');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var t=a(this);if(!t.find("."+l)[0]){var i=a('ဆ ');i.on("click",f.tabDelete),t.append(i)}}),"string"!=typeof s.attr("lay-unauto"))if(o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+e)[0])return;o.append(c),s.attr("overflow",""),c.on("click",function(a){o[this.title?"removeClass":"addClass"](t),this.title=this.title?"":"收缩"})}else o.find("."+e).remove(),s.removeAttr("overflow")})},hideTabMore:function(t){var i=a(".layui-tab-title");t!==!0&&"tabmore"===a(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr("lay-filter"),s=t.parent(),c=t.siblings("."+d),y="string"==typeof s.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||y||c[0]||(i.find("."+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s["none"===c.css("display")?"addClass":"removeClass"](r+"ed"),"all"===i.attr("lay-shrink")&&s.siblings().removeClass(r+"ed"))),layui.event.call(this,e,"nav("+n+")",t)},collapse:function(){var t=a(this),i=t.find(".layui-colla-icon"),l=t.siblings(".layui-colla-content"),s=t.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),r="none"===l.css("display");if("string"==typeof s.attr("lay-accordion")){var c=s.children(".layui-colla-item").children("."+n);c.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),c.removeClass(n)}l[r?"addClass":"removeClass"](n),i.html(r?"":""),layui.event.call(this,e,"collapse("+o+")",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter="'+e+'"]':""}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find("."+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children("a").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css("marginLeft")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),"block"===f.css("display")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find("."+y).addClass(y+"d")},300))};a(o+l).each(function(i){var l=a(this),o=a(' '),h=l.find("."+r);l.find("."+c)[0]||(l.append(o),h.on("mouseenter",function(){b.call(this,o,l,i)}).on("mouseleave",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find("."+d).removeClass(n),l.find("."+y).removeClass(y+"d")},300))}),l.on("mouseleave",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find("a").each(function(){var t=a(this),i=(t.parent(),t.siblings("."+d));i[0]&&!t.children("."+y)[0]&&t.append(' '),t.off("click",f.clickThis).on("click",f.clickThis)})})},breadcrumb:function(){var t=".layui-breadcrumb";a(t+l).each(function(){var t=a(this),i="lay-separator",e=t.attr(i)||"/",l=t.find("a");l.next("span["+i+"]")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(""+e+" ")}),t.css("visibility","visible"))})},progress:function(){var t="layui-progress";a("."+t+l).each(function(){var i=a(this),e=i.find(".layui-progress-bar"),l=e.attr("lay-percent");e.css("width",function(){return/^.+\/.+$/.test(l)?100*new Function("return "+l)()+"%":l}()),i.attr("lay-showPercent")&&setTimeout(function(){e.html(''+l+" ")},350)})},collapse:function(){var t="layui-collapse";a("."+t+l).each(function(){var t=a(this).find(".layui-colla-item");t.each(function(){var t=a(this),i=t.find(".layui-colla-title"),e=t.find(".layui-colla-content"),l="none"===e.css("display");i.find(".layui-colla-icon").remove(),i.append(''+(l?"":"")+" "),i.off("click",f.collapse).on("click",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=".layui-tab-title li";b.on("click",v,f.tabClick),b.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),t(e,p)});
\ No newline at end of file
diff --git a/src/main/resources/static/layui/lay/modules/flow.js b/src/main/resources/static/layui/lay/modules/flow.js
new file mode 100644
index 0000000..8a80c05
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/flow.js
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t=' ';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多 ",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});
\ No newline at end of file
diff --git a/src/main/resources/static/layui/lay/modules/form.js b/src/main/resources/static/layui/lay/modules/form.js
new file mode 100644
index 0000000..daa8ce5
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/form.js
@@ -0,0 +1,2 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,a=layui.hint(),n=layui.device(),l="form",r=".layui-form",s="layui-this",o="layui-hide",c="layui-disabled",u=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:function(e){if(!e||isNaN(e))return"只能填写数字"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};u.prototype.set=function(e){var i=this;return t.extend(!0,i.config,e),i},u.prototype.verify=function(e){var i=this;return t.extend(!0,i.config.verify,e),i},u.prototype.on=function(e,t){return layui.onevent.call(this,l,e,t)},u.prototype.val=function(e,i){var a=t(r+'[lay-filter="'+e+'"]');a.each(function(e,a){var n=t(this);layui.each(i,function(e,t){var i,a=n.find('[name="'+e+'"]');a[0]&&(i=a[0].type,"checkbox"===i?a[0].checked=t:"radio"===i?a.each(function(){this.value===t&&(this.checked=!0)}):a.val(t))})}),f.render(null,e)},u.prototype.render=function(e,i){var n=this,u=t(r+function(){return i?'[lay-filter="'+i+'"]':""}()),d={select:function(){var e,i="请选择",a="layui-form-select",n="layui-select-title",r="layui-select-none",d="",f=u.find("select"),v=function(i,l){t(i.target).parent().hasClass(n)&&!l||(t("."+a).removeClass(a+"ed "+a+"up"),e&&d&&e.val(d)),e=null},y=function(i,u,f){var y,p=t(this),m=i.find("."+n),k=m.find("input"),x=i.find("dl"),g=x.children("dd"),b=this.selectedIndex;if(!u){var C=function(){var e=i.offset().top+i.outerHeight()+5-h.scrollTop(),t=x.outerHeight();b=p[0].selectedIndex,i.addClass(a+"ed"),g.removeClass(o),y=null,g.eq(b).addClass(s).siblings().removeClass(s),e+t>h.height()&&e>=t&&i.addClass(a+"up"),$()},w=function(e){i.removeClass(a+"ed "+a+"up"),k.blur(),y=null,e||T(k.val(),function(e){var i=p[0].selectedIndex;e&&(d=t(p[0].options[i]).html(),0===i&&d===k.attr("placeholder")&&(d=""),k.val(d||""))})},$=function(){var e=x.children("dd."+s);if(e[0]){var t=e.position().top,i=x.height(),a=e.height();t>i&&x.scrollTop(t+x.scrollTop()-i+a-5),t<0&&x.scrollTop(t+x.scrollTop()-5)}};m.on("click",function(e){i.hasClass(a+"ed")?w():(v(e,!0),C()),x.find("."+r).remove()}),m.find(".layui-edge").on("click",function(){k.focus()}),k.on("keyup",function(e){var t=e.keyCode;9===t&&C()}).on("keydown",function(e){var t=e.keyCode;9===t&&w();var i=function(t,a){var n,l;e.preventDefault();var r=function(){var e=x.children("dd."+s);if(x.children("dd."+o)[0]&&"next"===t){var i=x.children("dd:not(."+o+",."+c+")"),n=i.eq(0).index();if(n>=0&&n无匹配项'):x.find("."+r).remove()},"keyup"),""===t&&x.find("."+r).remove(),void $())};f&&k.on("keyup",j).on("blur",function(i){var a=p[0].selectedIndex;e=k,d=t(p[0].options[a]).html(),0===a&&d===k.attr("placeholder")&&(d=""),setTimeout(function(){T(k.val(),function(e){d||k.val("")},"blur")},200)}),g.on("click",function(){var e=t(this),a=e.attr("lay-value"),n=p.attr("lay-filter");return!e.hasClass(c)&&(e.hasClass("layui-select-tips")?k.val(""):(k.val(e.text()),e.addClass(s)),e.siblings().removeClass(s),p.val(a).removeClass("layui-form-danger"),layui.event.call(this,l,"select("+n+")",{elem:p[0],value:a,othis:i}),w(!0),!1)}),i.find("dl>dt").on("click",function(e){return!1}),t(document).off("click",v).on("click",v)}};f.each(function(e,l){var r=t(this),o=r.next("."+a),u=this.disabled,d=l.value,f=t(l.options[l.selectedIndex]),v=l.options[0];if("string"==typeof r.attr("lay-ignore"))return r.show();var h="string"==typeof r.attr("lay-search"),p=v?v.value?i:v.innerHTML||i:i,m=t(['','
',' ','
','
',function(e){var t=[];return layui.each(e,function(e,a){0!==e||a.value?"optgroup"===a.tagName.toLowerCase()?t.push(""+a.label+" "):t.push(''+a.innerHTML+" "):t.push(''+(a.innerHTML||i)+" ")}),0===t.length&&t.push('没有选项 '),t.join("")}(r.find("*"))+" ","
"].join(""));o[0]&&o.remove(),r.after(m),y.call(this,m,u,h)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},i=u.find("input[type=checkbox]"),a=function(e,i){var a=t(this);e.on("click",function(){var t=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(i[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(i[1]).find("em").text(n[0])),layui.event.call(a[0],l,i[2]+"("+t+")",{elem:a[0],value:a[0].value,othis:e}))})};i.each(function(i,n){var l=t(this),r=l.attr("lay-skin"),s=(l.attr("lay-text")||"").split("|"),o=this.disabled;"switch"===r&&(r="_"+r);var u=e[r]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+u[0]),f=t(['",function(){var e=n.title.replace(/\s/g,""),t={checkbox:[e?""+n.title+" ":"",' '].join(""),_switch:""+((n.checked?s[0]:s[1])||"")+" "};return t[r]||t.checkbox}(),"
"].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e="layui-form-radio",i=["",""],a=u.find("input[type=radio]"),n=function(a){var n=t(this),s="layui-anim-scaleSpring";a.on("click",function(){var o=n[0].name,c=n.parents(r),u=n.attr("lay-filter"),d=c.find("input[name="+o.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=t(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(s).html(i[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(s).html(i[0]),layui.event.call(n[0],l,"radio("+u+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=t(this),s=r.next("."+e),o=this.disabled;if("string"==typeof r.attr("lay-ignore"))return r.show();s[0]&&s.remove();var u=t(['','
'+i[l.checked?0:1]+" ","
"+function(){var e=l.title||"";return"string"==typeof r.next().attr("lay-radio")&&(e=r.next().html(),r.next().remove()),e}()+"
","
"].join(""));r.after(u),n.call(this,u)})}};return e?d[e]?d[e]():a.error("不支持的"+e+"表单渲染"):layui.each(d,function(e,t){t()}),n};var d=function(){var e=t(this),a=f.config.verify,s=null,o="layui-form-danger",c={},u=e.parents(r),d=u.find("*[lay-verify]"),v=e.parents("form")[0],h=u.find("input,select,textarea"),y=e.attr("lay-filter");if(layui.each(d,function(e,l){var r=t(this),c=r.attr("lay-verify").split("|"),u=r.attr("lay-verType"),d=r.val();if(r.removeClass(o),layui.each(c,function(e,t){var c,f="",v="function"==typeof a[t];if(a[t]){var c=v?f=a[t](d,l):!a[t][0].test(d);if(f=f||a[t][1],c)return"tips"===u?i.tips(f,function(){return"string"==typeof r.attr("lay-ignore")||"select"!==l.tagName.toLowerCase()&&!/^checkbox|radio$/.test(l.type)?r:r.next()}(),{tips:1}):"alert"===u?i.alert(f,{title:"提示",shadeClose:!0}):i.msg(f,{icon:5,shift:6}),n.android||n.ios||l.focus(),r.addClass(o),s=!0}}),s)return s}),s)return!1;var p={};return layui.each(h,function(e,t){if(t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name){if(/^.*\[\]$/.test(t.name)){var i=t.name.match(/^(.*)\[\]$/g)[0];p[i]=0|p[i],t.name=t.name.replace(/^(.*)\[\]$/,"$1["+p[i]++ +"]")}/^checkbox|radio$/.test(t.type)&&!t.checked||(c[t.name]=t.value)}}),layui.event.call(this,l,"submit("+y+")",{elem:this,form:v,field:c})},f=new u,v=t(document),h=t(window);f.render(),v.on("reset",r,function(){var e=t(this).attr("lay-filter");setTimeout(function(){f.render(null,e)},50)}),v.on("submit",r,d).on("click","*[lay-submit]",d),e(l,f)});
\ No newline at end of file
diff --git a/src/main/resources/static/layui/lay/modules/jquery.js b/src/main/resources/static/layui/lay/modules/jquery.js
new file mode 100644
index 0000000..242696a
--- /dev/null
+++ b/src/main/resources/static/layui/lay/modules/jquery.js
@@ -0,0 +1,5 @@
+/** layui-v2.4.5 MIT License By https://www.layui.com */
+ ;!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t=!!e&&"length"in e&&e.length,n=pe.type(e);return"function"!==n&&!pe.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c ")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),we=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML=" ",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$1']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),
+l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML=" ","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML=" ",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length a ",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""," "],legend:[1,""," "],area:[1,""," "],param:[1,""," "],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:fe.htmlSerialize?[0,"",""]:[1,"X","
"]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s ]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 开灯
+ 护眼
+ 字体:大 中 小
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/books/book_detail.html b/src/main/resources/templates/books/book_detail.html
new file mode 100644
index 0000000..9df71af
--- /dev/null
+++ b/src/main/resources/templates/books/book_detail.html
@@ -0,0 +1,375 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
更新:
+
评分:
+
点击:
+
+
+
+
+
+
+
+
+
+
开始阅读
+
加入书架
+
+
我的书架
+
下载TXT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/books/book_index.html b/src/main/resources/templates/books/book_index.html
new file mode 100644
index 0000000..4efdeb2
--- /dev/null
+++ b/src/main/resources/templates/books/book_index.html
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ↓直达页面底部
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/books/book_search.html b/src/main/resources/templates/books/book_search.html
new file mode 100644
index 0000000..5ab897c
--- /dev/null
+++ b/src/main/resources/templates/books/book_search.html
@@ -0,0 +1,260 @@
+
+
+
+
+
+
+
+ 精品小说楼_小说列表
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/books/index.html b/src/main/resources/templates/books/index.html
new file mode 100644
index 0000000..610175c
--- /dev/null
+++ b/src/main/resources/templates/books/index.html
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+ 精品小说楼
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/books/soft_book_search.html b/src/main/resources/templates/books/soft_book_search.html
new file mode 100644
index 0000000..336c2be
--- /dev/null
+++ b/src/main/resources/templates/books/soft_book_search.html
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+ 精品小说楼_轻小说专区
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/common/css.html b/src/main/resources/templates/common/css.html
new file mode 100644
index 0000000..8e18b4a
--- /dev/null
+++ b/src/main/resources/templates/common/css.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/common/footer.html b/src/main/resources/templates/common/footer.html
new file mode 100644
index 0000000..d2b29b2
--- /dev/null
+++ b/src/main/resources/templates/common/footer.html
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/src/main/resources/templates/common/js.html b/src/main/resources/templates/common/js.html
new file mode 100644
index 0000000..8a6fa1d
--- /dev/null
+++ b/src/main/resources/templates/common/js.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/main/resources/templates/common/soft_footer.html b/src/main/resources/templates/common/soft_footer.html
new file mode 100644
index 0000000..ba77ed5
--- /dev/null
+++ b/src/main/resources/templates/common/soft_footer.html
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
new file mode 100644
index 0000000..7a7a5cd
--- /dev/null
+++ b/src/main/resources/templates/index.html
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+ 看小说吧
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 龙虎榜
+ 热点
+ 分类
+ 全本
+ 足迹
+ 收藏
+
+
+
+
+
+
+
+
+
+
+
+
+ 内容
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/user/login.html b/src/main/resources/templates/user/login.html
new file mode 100644
index 0000000..13c6f63
--- /dev/null
+++ b/src/main/resources/templates/user/login.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+ 登录|注册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/xyz/zinglizingli/search/SearchApplicationTests.java b/src/test/java/xyz/zinglizingli/search/SearchApplicationTests.java
new file mode 100644
index 0000000..d856280
--- /dev/null
+++ b/src/test/java/xyz/zinglizingli/search/SearchApplicationTests.java
@@ -0,0 +1,16 @@
+package xyz.zinglizingli.search;
+
+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 SearchApplicationTests {
+
+ @Test
+ public void contextLoads() {
+ }
+
+}