[
  {
    "path": ".gitignore",
    "content": "\n/.settings\n/bin\n*/target/*\n/logs\n*/out/\n\n# filter config files, except .gitignore\n*.MF\n!.gitignore\n*.iml\n*.exe\n# eclipse ignore\n.project\n.classpath\n# IDEA ignore\n.idea\n.class\n*.class\n*.log\n!application.properties\n"
  },
  {
    "path": "README.md",
    "content": "## 致歉\n由于自己懒以及身体对issuse 解决的不及时。请大家以后提issuse 的时候写清楚 模块名 比如“springboot-SpringSecurity4” 和问题，我会抽时间抓紧解决。\n\n## springboot-SpringSecurity0  \n\n包含两部分代码：\n\n* 第一是  博客 springboot+mybatis＋SpringSecurity 实现用户角色数据库管理   地址：http://blog.csdn.net/u012373815/article/details/54632176\n\n* 第二是  博客 springBoot+springSecurity验证密码MD5加密  地址：http://blog.csdn.net/u012373815/article/details/54927070\n\n## springboot-SpringSecurity1  \n\n*  博客 springBoot+springSecurity 数据库动态管理用户、角色、权限（二）   地址：http://blog.csdn.net/u012373815/article/details/54633046\n\n## springboot-SpringSecurity2\n\n*  博客  springboot+security restful权限控制官方推荐（五）   地址：http://blog.csdn.net/u012373815/article/details/59749385\n\n## springboot-SpringSecurity3\n\n*  博客  springBoot+springSecurity 动态管理Restful风格权限（三） 地址：http://blog.csdn.net/u012373815/article/details/55225079  \n\n## springboot-SpringSecurity4\n* 实战，项目中正在用\n\n## springboot-WebSocket  \n\n包含三部分代码,三部分代码有交合:\n\n* 第一是  博客 spring boot ＋WebSocket 广播式（一）地址：http://blog.csdn.net/u012373815/article/details/54375195  中所示代码\n\n* 第二是  博客 spring boot ＋WebSocket 广播式（二）地址：http://blog.csdn.net/u012373815/article/details/54377937   中所示代码\n \n* 第三是  博客 spring boot ＋WebSocket（三） 点对点式 地址： http://blog.csdn.net/u012373815/article/details/54380476  中所示代码\n\n\n\n## springboot-Cache\n\n包含两部分代码：\n\n* 第一部分是 博客 springboot的缓存技术 地址： http://blog.csdn.net/u012373815/article/details/54564076  \n\n* 第二部分是 博客 springboot缓存篇（二）－redis 做缓存 地址：http://blog.csdn.net/u012373815/article/details/54572687\n\n## springboot-Cache2\n\n* 是  博客  springboot缓存 之 GuavaCacheManager   地址：http://blog.csdn.net/u012373815/article/details/60468033\n\n\n\n## springboot-shiro\n\n* 是博客  springboot集成shiro 实现权限控制   地址：http://blog.csdn.net/u012373815/article/details/57532292\n\n##springboot-shior2\n\n是使用shior 框架调取用户权限服务，进行登录权限验证的例子，其中的用户权限服务没有写，都是用TODO 标示出来了，使用时可以根据各自的用户权限服务进行编码替换\n\nspringboot-shiro2 也是和dubbo 的结合例子是 消费者的示例。\n\n## springboot-swagger-ui\n* 博客 spring boot ＋Swagger-ui 自动生成API文档 地址： https://blog.csdn.net/u012373815/article/details/82685962\n\n## springBoot-Quartz\n* 博客 springBoot-Quartz 定时任务 地址： https://abelyang.blog.csdn.net/article/details/86740625\n\n## springboot 整合mybatis2\n* springboot 整合mybatis2 更简便的整合方式地址： https://abelyang.blog.csdn.net/article/details/89296273\n\n## springboot+Kafka\n* kafka 与 sprigboot 的结合，springboot 从Kafka中读取数据的小例子地址： https://abelyang.blog.csdn.net/article/details/89296305\n\n## springboot+es\n* Elasticsearch 与 sprigboot 的结合，springboot 操作es的小例子地址： https://abelyang.blog.csdn.net/article/details/89296320\n\n## Springboot多数据源切换\n* springboot 多个数据源的配置， 一个springboot 项目操作多个数据库的数据：https://abelyang.blog.csdn.net/article/details/89296341\n\n##springboot-dubbo\n\n该项目是Springboot 和 dubbo 结合的例子，是provider 的示例，提供服务。简单的写了一些用户和权限的接口没有写的很完整，主要是为了提现dubbo 服务\nSpringboot-shiro2 也是和dubbo 的结合例子是 消费者的示例。\n\n\n\n##未完待续。。。\n"
  },
  {
    "path": "abel-parent/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    \n    <groupId>cn.abel</groupId>\n    <artifactId>abel-parent</artifactId>\n    <packaging>pom</packaging>\n    <version>1.0.0-SNAPSHOT</version>\n    \n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    \n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <shiro.version>1.4.0</shiro.version>\n        <mysql.version>5.1.47</mysql.version>\n    </properties>\n    \n    <dependencyManagement>\n        <dependencies>\n            <!--<dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-test</artifactId>\n                <scope>test</scope>\n            </dependency>-->\n            <!--<dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-devtools</artifactId>\n                <optional>true</optional>\n                <scope>runtime</scope>\n            </dependency>-->\n            \n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>3.7</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-collections4</artifactId>\n                <version>4.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-pool2</artifactId>\n                <version>2.6.0</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>dom4j</groupId>\n                <artifactId>dom4j</artifactId>\n                <version>1.6.1</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>${mysql.version}</version>\n                <scope>runtime</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid</artifactId>\n                <version>1.1.10</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-spring</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-ehcache</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-quartz</artifactId>\n                <version>${shiro.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.opensymphony.quartz</groupId>\n                        <artifactId>quartz</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>net.mingsoft</groupId>\n                <artifactId>shiro-freemarker-tags</artifactId>\n                <version>1.0.0</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-core</artifactId>\n                <version>5.3.4.Final</version>\n            </dependency>\n\t\t\t\n\t\t\t<dependency>\n\t\t\t    <groupId>com.fasterxml.jackson.core</groupId>\n\t\t\t    <artifactId>jackson-core</artifactId>\n\t\t\t    <version>2.9.7</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t    <groupId>com.fasterxml.jackson.core</groupId>\n\t\t\t    <artifactId>jackson-databind</artifactId>\n\t\t\t    <version>2.9.9.1</version>\n\t\t\t</dependency>\n    \n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>fastjson</artifactId>\n                <version>1.2.58</version>\n            </dependency>\n\n            <!--<dependency>\n                <groupId>redis.clients</groupId>\n                <artifactId>jedis</artifactId>\n                <version>2.9.0</version>\n            </dependency>-->\n            <dependency>\n                <groupId>org.mybatis.spring.boot</groupId>\n                <artifactId>mybatis-spring-boot-starter</artifactId>\n                <version>1.3.2</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.pagehelper</groupId>\n                <artifactId>pagehelper-spring-boot-starter</artifactId>\n                <version>1.2.5</version>\n            </dependency>\n\t\t\t\n\t\t\t<dependency>\n\t\t\t    <groupId>org.quartz-scheduler</groupId>\n\t\t\t    <artifactId>quartz</artifactId>\n\t\t\t    <version>2.2.1</version>\n\t\t\t</dependency>\n    \n            <!-- dubbo log4j替换为logback -->\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>dubbo</artifactId>\n                <version>2.8.4</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>log4j</groupId>\n                        <artifactId>log4j</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>log4j-over-slf4j</artifactId>\n                <version>1.7.25</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.zookeeper</groupId>\n                <artifactId>zookeeper</artifactId>\n                <version>3.4.13</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-log4j12</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>log4j</groupId>\n                        <artifactId>log4j</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            \n            <!--dubbox-->\n            <dependency>\n                <groupId>org.jboss.resteasy</groupId>\n                <artifactId>resteasy-jaxrs</artifactId>\n                <version>3.0.26.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.resteasy</groupId>\n                <artifactId>resteasy-client</artifactId>\n                <version>3.0.26.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.resteasy</groupId>\n                <artifactId>resteasy-jackson-provider</artifactId>\n                <version>3.0.26.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.validation</groupId>\n                <artifactId>validation-api</artifactId>\n                <version>2.0.1.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate.validator</groupId>\n                <artifactId>hibernate-validator</artifactId>\n                <version>6.0.13.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>com.101tec</groupId>\n                <artifactId>zkclient</artifactId>\n                <version>0.10</version>\n            </dependency>\n\t\t\t\n\t\t\t<!-- 阿里大于回调 -->\n\t\t\t<dependency>\n\t\t\t    <groupId>com.google.code.gson</groupId>\n\t\t\t    <artifactId>gson</artifactId>\n\t\t\t    <version>2.8.5</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t    <groupId>org.apache.httpcomponents</groupId>\n\t\t\t    <artifactId>httpcore</artifactId>\n\t\t\t    <version>4.4.10</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t    <groupId>org.apache.httpcomponents</groupId>\n\t\t\t    <artifactId>httpcore-nio</artifactId>\n\t\t\t    <version>4.4.10</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t    <groupId>org.apache.httpcomponents</groupId>\n\t\t\t    <artifactId>httpclient</artifactId>\n\t\t\t    <version>4.5.6</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t    <groupId>org.apache.httpcomponents</groupId>\n\t\t\t    <artifactId>httpasyncclient</artifactId>\n\t\t\t    <version>4.1.4</version>\n\t\t\t</dependency>\n    \n            <dependency>\n                <groupId>com.aliyun.oss</groupId>\n                <artifactId>aliyun-sdk-oss</artifactId>\n                <version>3.3.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.aliyun</groupId>\n                <artifactId>aliyun-java-sdk-sts</artifactId>\n                <version>3.0.0</version>\n            </dependency>\n    \n            <dependency>\n                <groupId>com.aliyun</groupId>\n                <artifactId>aliyun-java-sdk-core</artifactId>\n                <version>4.2.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.aliyun</groupId>\n                <artifactId>aliyun-java-sdk-dysmsapi</artifactId>\n                <version>1.1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.aliyun.mns</groupId>\n                <artifactId>aliyun-sdk-mns</artifactId>\n                <version>1.1.8.6</version>\n            </dependency>\n\t\t\t\n            \n            <!-- Mapping映射 -->\n            <dependency>\n                <groupId>org.mapstruct</groupId>\n                <artifactId>mapstruct-jdk8</artifactId>\n                <version>1.1.0.Final</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    \n    <distributionManagement>\n        <repository>\n            <id>Releases</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/releases</url>\n        </repository>\n        <snapshotRepository>\n            <id>Snapshots</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/snapshots</url>\n        </snapshotRepository>\n    </distributionManagement>\n    \n    <profiles>\n        <profile>\n            <id>local</id>\n            <properties>\n                <package.environment>local</package.environment>\n            </properties>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n            </activation>\n        </profile>\n        <profile>\n            <id>dev</id>\n            <properties>\n                <package.environment>dev</package.environment>\n            </properties>\n        </profile>\n        <profile>\n            <id>online</id>\n            <properties>\n                <package.environment>online</package.environment>\n            </properties>\n        </profile>\n        <profile>\n            <id>test</id>\n            <properties>\n                <package.environment>test</package.environment>\n            </properties>\n        </profile>\n        <profile>\n            <id>test-ali</id>\n            <properties>\n                <package.environment>test-ali</package.environment>\n            </properties>\n        </profile>\n    </profiles>\n    \n    <build>\n        <finalName>${project.artifactId}-${project.version}</finalName>\n        <resources>\n            <resource>\n                <directory>src/main/resources/${package.environment}</directory>\n                <includes>\n                    <include>*.*</include>\n                </includes>\n            </resource>\n            <resource>\n                <directory>src/main/resources</directory>\n                <excludes>\n                    <exclude>local/**</exclude>\n                    <exclude>dev/**</exclude>\n                    <exclude>test/**</exclude>\n                    <exclude>test-ali/**</exclude>\n                    <exclude>online/**</exclude>\n                </excludes>\n            </resource>\n        </resources>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-maven-plugin</artifactId>\n                    <configuration>\n                        <!--允许包含本地包-->\n                        <includeSystemScope>true</includeSystemScope>\n                        <!--fork:如果没有该项配置devtools不会起作用，即应用不会restart -->\n                        <fork>true</fork>\n                        <!--支持静态文件热部署-->\n                        <addResources>true</addResources>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>3.6.0</version>\n                    <configuration>\n                        <encoding>UTF-8</encoding>\n                        <source>1.8</source>\n                        <target>1.8</target>\n                        <annotationProcessorPaths>\n                            <path>\n                                <groupId>org.mapstruct</groupId>\n                                <artifactId>mapstruct-processor</artifactId>\n                                <version>1.1.0.Final</version>\n                            </path>\n                        </annotationProcessorPaths>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n\n</project>\n"
  },
  {
    "path": "abel-util/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>abel-util</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n    <parent>\n        <groupId>cn.abel</groupId>\n        <artifactId>abel-parent</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-collections4</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <version>5.1.3.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>2.0.4.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.9.8</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>4.0.1</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n</project>"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/code/InfoCode.java",
    "content": "package cn.abel.code;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.lang3.builder.ToStringStyle;\n\n/**\n * 返回响应 Created by liyunfeng\n */\npublic enum InfoCode {\n\n    //系统错误从200~10000\n    SUCCESS(200, \"OK\"),\n    TIME_OUT(300, \"超时\"),\n\n    //业务相关从10000自增\n    // 10000开始\n    INVALID_REQUEST(10000, \"不支持的请求方式\"),\n\n    //用户相关（20000自增）\n    REQUEST_PARAM_ERROR(20000, \"传入参数错误\"),\n    REGISTER_TYPE_ERROR(20001, \"不支持的注册类型\"),\n    INVALID_SIGN(20002, \"签名无效\"),\n    USER_LOGIN_EXIST(20003, \"用户已存在\"),\n    USER_LOGIN_NOT_EXIST(20008, \"用户不存在\"),\n    PASSWORD_ERROR(20009, \"用户名或密码错误\"),\n    INVALID_TOKEN(20010, \"无效token\"),\n    INVALID_LOGIN(20011, \"登录失效，重新登录\"),\n    PASSWORD_SAME(20017, \"密码重复\"),\n    OLD_PASSWORD_ERROR(20018, \"密码错误，不能修改\"),\n    LOGIN_FAIL(20024, \"登录失败\"),\n    VISITOR_REGISTER_FAIL(20025, \"游客注册失败\"),\n    TOKEN_EXIST(20033, \"token重复\"),\n    LOGIN_TYPE_EXIST(20034, \"登录方式已存在\"),\n    USER_PROFILE_SEARCH_ERROR(20035, \"用户查询失败\"),\n    USER_PROFILE_LOCK(20036, \"用户已锁定\"),\n    ACCOUNT_SEARCH_FAIL(20037, \"账号查询失败\"),\n    LOGIN_NAME_TYPE_ERROR(20038, \"登录名不为空时，登录方式不能为空\"),\n    PASSWORD_SIMPLE_ERROR(20042, \"密码错误，长度应为6-18，包含字母、数字和特殊字符\"),\n    PASSWORD_ERROR_MORE_THAN(20043,\"用户名密码连续错误已达5次，请15分钟后再试\"),\n    LOGIN_TYPE_ERROR(20044, \"不支持的登录类型\"),\n    SERVICE_UNAVAILABLE(50000, \"操作失败，请重试\");\n\n    private int status;\n\n    private String msg;\n\n    private InfoCode(int status, String msg) {\n        this.status = status;\n        this.msg = msg;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);\n    }\n}\n"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/exception/AppRuntimeException.java",
    "content": "package cn.abel.exception;\n\n\nimport cn.abel.code.InfoCode;\n\n/**\n * 接口服务抛出的异常\n *\n */\npublic class AppRuntimeException extends RuntimeException {\n\n\tprivate static final long serialVersionUID = 2963760410777899525L;\n\tprivate InfoCode infoCode;\n\n\tpublic AppRuntimeException() {\n\t\tinfoCode = InfoCode.SERVICE_UNAVAILABLE;\n\t\t\n\t}\n\n\tpublic AppRuntimeException(InfoCode infoCode) {\n\t\tthis.infoCode = infoCode;\n\t}\n\t\n\tpublic AppRuntimeException(InfoCode infoCode, String message) {\n\t    super(message);\n\t    this.infoCode = infoCode;\n\t}\n\n\tpublic InfoCode getInfoCode() {\n\t\treturn infoCode;\n\t}\n\n}\n"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/exception/HttpExeption.java",
    "content": "package cn.abel.exception;\n\npublic class HttpExeption extends Exception {\n\t\n\tprivate static final long serialVersionUID = -4707210535385221192L;\n\n\tpublic HttpExeption() {\n\t}\n\n\tpublic HttpExeption(String msg) {\n\t\tsuper(msg);\n\t}\n\n\tpublic HttpExeption(String msg, Throwable e) {\n\t\tsuper(msg, e);\n\t}\n\n\tpublic HttpExeption(Throwable e) {\n\t\tsuper(e);\n\t}\n}"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/exception/ServiceException.java",
    "content": "package cn.abel.exception;\n\nimport cn.abel.code.*;\n\n/**\n * 服务异常类\n *\n */\n@SuppressWarnings(\"serial\")\npublic class ServiceException extends Exception {\n\n    //默认的错误码\n    private int errorCode = 500;\n\n    private String errorCodes;\n\n    public ServiceException() {\n    }\n\n    public ServiceException(Throwable e) {\n        super(e);\n    }\n\n    public ServiceException(int errorCode) {\n        this.errorCode = errorCode;\n    }\n\n    public int getErrorCode() {\n        return errorCode;\n    }\n\n    public String getErrorCodes() {\n        return errorCodes;\n    }\n\n    public ServiceException(InfoCode infoCode){\n        super(infoCode.getMsg());\n        this.errorCode = infoCode.getStatus();\n    }\n\n    public ServiceException(int errorCode, String msg) {\n        super(msg);\n        this.errorCode = errorCode;\n    }\n\n    public ServiceException(String errorCode, String msg) {\n        super(msg);\n        this.errorCodes = errorCode;\n    }\n\n    public ServiceException(int errorCode, String msg, Throwable e) {\n        super(msg, e);\n        this.errorCode = errorCode;\n    }\n\n    public ServiceException(int errorCode, Throwable e) {\n        super(e);\n        this.errorCode = errorCode;\n    }\n}\n"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/response/ResponseEntity.java",
    "content": "package cn.abel.response;\n\n\nimport cn.abel.code.*;\n\nimport java.util.HashMap;\n\n/**\n * Created by guoshan on 2018/3/21.\n * <p>\n * 服务端返回给前端或客户端使用\n */\npublic class ResponseEntity {\n    int status = 200;\n\n    String message = \"ok\";\n\n    Object data = new HashMap();\n\n\n    private ResponseEntity() {\n    }\n\n    public static ResponseEntity ok(Object data) {\n        ResponseEntity ResponseEntity = new ResponseEntity();\n        ResponseEntity.setData(data);\n        return ResponseEntity;\n    }\n\n    public static ResponseEntity error(InfoCode infoCode) {\n        ResponseEntity ResponseEntity = new ResponseEntity();\n        ResponseEntity.setStatus(infoCode.getStatus());\n        ResponseEntity.setMessage(infoCode.getMsg());\n        return ResponseEntity;\n    }\n\n    public static ResponseEntity ok() {\n        ResponseEntity ResponseEntity = new ResponseEntity();\n        return ResponseEntity;\n    }\n\n    public static ResponseEntity error(int code, String msg) {\n        ResponseEntity ResponseEntity = new ResponseEntity();\n        ResponseEntity.setStatus(code);\n        ResponseEntity.setMessage(msg);\n        return ResponseEntity;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public Object getData() {\n        return data == null ? new HashMap() : data;\n    }\n\n    public void setData(Object data) {\n        this.data = data;\n    }\n}\n"
  },
  {
    "path": "abel-util/src/main/java/cn/abel/utils/DateTimeUtils.java",
    "content": "package cn.abel.utils;\n\nimport cn.abel.exception.ServiceException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.commons.lang3.time.DateUtils;\n\nimport java.text.ParseException;\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.ZoneId;\nimport java.util.Calendar;\nimport java.util.Date;\n\n/**\n * 日期util。\n */\npublic class DateTimeUtils {\n\n    /**\n     * 一分钟。\n     */\n    public static final int ONE_MINUTE = 60 * 1000;\n\n    /**\n     * 一小时。\n     */\n    public static final int ONE_HOUR = 60 * ONE_MINUTE;\n\n    /**\n     * 一天。\n     */\n    public static final int ONE_DAY = 24 * ONE_HOUR;\n\n\n    public static final String DEFAULT_DATETIME_PATTERN = \"yyyy-MM-dd HH:mm:ss\";\n    public static final String DEFAULT_DATE_PATTERN = \"yyyy-MM-dd\";\n    private static final int ARG_ERROR_CODE = 400;\n    private static final String ARG_ERROR = \"输入的参数有误\";\n\n\n    /**\n     * 根据给定的格式将时间转为字符串。\n     *\n     * @param dateTime\n     * @param pattern\n     * @return\n     */\n    public static String format(Date dateTime, String pattern) {\n        if (dateTime == null || pattern == null) {\n            return StringUtils.EMPTY;\n        }\n\n        return DateFormatUtils.format(dateTime, pattern);\n    }\n\n    /**\n     * 将时间转为默认格式的字符串。\n     *\n     * @param dateTime\n     * @return\n     */\n    public static String format(Date dateTime) {\n        return format(dateTime, DEFAULT_DATETIME_PATTERN);\n    }\n\n    /**\n     * 根据给定的格式获取当前日期的字符串。\n     *\n     * @param pattern\n     * @return\n     */\n    public static String formatCurrent(String pattern) {\n        return format(new Date(), pattern);\n    }\n\n    /**\n     * 获取当前日期的字符串。\n     *\n     * @return\n     */\n    public static String formatCurrent() {\n        return format(new Date(), DEFAULT_DATE_PATTERN);\n    }\n\n    /**\n     * 去除时间中的时分秒毫秒，只保留日期部分。\n     *\n     * @param dateTime\n     * @return\n     */\n    public static Date removeTime(Date dateTime) {\n        if (dateTime == null) {\n            return null;\n        }\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(dateTime);\n        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);\n        calendar.set(Calendar.MILLISECOND, 0);\n        return calendar.getTime();\n    }\n\n    /**\n     * 获取明天的日期。\n     *\n     * @return\n     */\n    public static Date getTomorrowDate() {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(new Date());\n        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);\n        calendar.set(Calendar.MILLISECOND, 0);\n        calendar.add(Calendar.DATE, 1);\n        return calendar.getTime();\n    }\n\n    /**\n     * 获取昨天的日期。\n     *\n     * @return\n     */\n    public static Date getYesterdayDate() {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(new Date());\n        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);\n        calendar.set(Calendar.MILLISECOND, 0);\n        calendar.add(Calendar.DATE, -1);\n        return calendar.getTime();\n    }\n\n    /**\n     * 根据给定的格式将时间字符串转化成{@link Date}对象。\n     *\n     * @param dateTimeStr\n     * @param pattern\n     * @return\n     * @throws ServiceException\n     */\n    public static Date parse(String dateTimeStr, String pattern) throws ServiceException {\n        if (dateTimeStr == null || pattern == null) {\n            return null;\n        }\n        try {\n            return DateUtils.parseDate(dateTimeStr, pattern);\n        } catch (ParseException e) {\n            throw new ServiceException(ARG_ERROR_CODE, ARG_ERROR);\n        }\n    }\n\n    /**\n     * 将时间字符串根据默认格式转换成{@link Date}对象。\n     *\n     * @param dateTimeStr\n     * @return\n     * @throws ServiceException\n     */\n    public static Date parse(String dateTimeStr) throws ServiceException {\n        return parse(dateTimeStr, DEFAULT_DATETIME_PATTERN);\n    }\n\n    /**\n     * 获取日期中的月份。\n     *\n     * @param date\n     * @return\n     */\n    public static int getMonth(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        return calendar.get(Calendar.MONTH) + 1;\n    }\n\n    /**\n     * 获取日期中的年份。\n     *\n     * @param date\n     * @return\n     */\n    public static int getYear(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        return calendar.get(Calendar.YEAR);\n    }\n\n    /**\n     * 增加日期。\n     *\n     * @param date\n     * @param days\n     * @return\n     * @throws ServiceException\n     */\n    public static Date dateAdd(Date date, int days) throws ServiceException {\n        if (date == null) {\n            throw new ServiceException(ARG_ERROR_CODE, ARG_ERROR);\n        }\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        calendar.add(Calendar.DATE, days);\n        return calendar.getTime();\n    }\n\n    /**\n     * 增加月份。\n     *\n     * @param date\n     * @param months\n     * @return\n     * @throws ServiceException\n     */\n    public static Date monthAdd(Date date, int months) throws ServiceException {\n        if (date == null) {\n            throw new ServiceException(ARG_ERROR_CODE, ARG_ERROR);\n        }\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        calendar.add(Calendar.MONTH, months);\n        return calendar.getTime();\n    }\n\n    /**\n     * 获取两个日期之间的差值。\n     *\n     * @param one\n     * @param two\n     * @return\n     * @throws ServiceException\n     */\n    public static int dateDiff(Date one, Date two) throws ServiceException {\n        if (one == null || two == null) {\n            throw new ServiceException(ARG_ERROR_CODE, ARG_ERROR);\n        }\n        long diff = Math.abs((one.getTime() - two.getTime()) / (1000 * 3600 * 24));\n        return new Long(diff).intValue();\n    }\n\n\n    /**\n     * 计算几天前的时间\n     *\n     * @param date 当前时间\n     * @param day  几天前\n     * @return\n     */\n    public static Date getDateBefore(Date date, int day) {\n        Calendar now = Calendar.getInstance();\n        now.setTime(date);\n        now.set(Calendar.DATE, now.get(Calendar.DATE) - day);\n        return now.getTime();\n    }\n\n    /**\n     * 获取当前月第一天\n     *\n     * @return Date\n     * @throws ParseException\n     */\n    public static Date getFirstAndLastOfMonth() {\n        LocalDate today = LocalDate.now();\n        LocalDate firstDay = LocalDate.of(today.getYear(),today.getMonth(),1);\n        ZoneId zone = ZoneId.systemDefault();\n        Instant instant = firstDay.atStartOfDay().atZone(zone).toInstant();\n        return Date.from(instant);\n    }\n\n    /**\n     * 获取当前周第一天\n     *\n     * @return Date\n     * @throws ParseException\n     */\n    public static Date getWeekFirstDate(){\n        Calendar cal = Calendar.getInstance();\n        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);\n        cal.set(Calendar.HOUR_OF_DAY, 0);\n        cal.set(Calendar.MINUTE, 0);\n        cal.set(Calendar.SECOND, 0);\n        cal.set(Calendar.MILLISECOND, 0);\n        Date date = cal.getTime();\n        return date;\n    }\n    \n}\n"
  },
  {
    "path": "springWebSocket/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us.example</groupId>\n    <artifactId>springWebSocket</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.example.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n    <dependencies>\n\n        <!-- 核心模块，包括自动配置支持、日志和YAML -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <!-- 测试模块，包括JUnit、Hamcrest、Mockito -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!-- 引入Web模块 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- SpringWebSocket依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-websocket</artifactId>\n        </dependency>\n\n        <!-- 引入security模块 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n    </dependencies>\n    <build>\n        <plugins>\n            <!--&lt;!&ndash;打依赖包&ndash;&gt;-->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-shade-plugin</artifactId>\n                <version>2.3</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>shade</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\n/**\n * Created by yangyibo on 16/12/29.\n */\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\n@EnableScheduling\npublic class Application {\n\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n}"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/bean/Message.java",
    "content": "package com.us.example.bean;\n\n/**\n * Created by yangyibo on 16/12/29.\n * 浏览器向服务器发送的消息使用此类接受\n */\npublic class Message {\n    private String name;\n\n    public String getName(){\n        return name;\n    }\n}"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/bean/Response.java",
    "content": "package com.us.example.bean;\n\n/**\n * Created by yangyibo on 16/12/29.\n * 服务器向浏览器发送的此类消息。\n */\npublic class Response {\n    public void setResponseMessage(String responseMessage) {\n        this.responseMessage = responseMessage;\n    }\n\n    private String responseMessage;\n    public Response(String responseMessage){\n        this.responseMessage = responseMessage;\n    }\n    public String getResponseMessage(){\n        return responseMessage;\n    }\n}"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/config/WebSecurityConfig.java",
    "content": "package com.us.example.config;\r\n\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\r\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\r\nimport org.springframework.security.config.annotation.web.builders.WebSecurity;\r\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\r\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\r\n\r\n@Configuration\r\n@EnableWebSecurity\r\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter{\r\n    @Override\r\n    protected void configure(HttpSecurity http) throws Exception {\r\n        http\r\n                .authorizeRequests()\r\n                .antMatchers(\"/\",\"/login\").permitAll()//根路径和/login路径不拦截\r\n                .anyRequest().authenticated()\r\n                .and()\r\n                .formLogin()\r\n                .loginPage(\"/login\") //2登陆页面路径为/login\r\n                .defaultSuccessUrl(\"/chat\") //3登陆成功转向chat页面\r\n                .permitAll()\r\n                .and()\r\n                .logout()\r\n                .permitAll();\r\n    }\r\n\r\n    //4在内存中配置两个用户 wyf 和 wisely ,密码和用户名一致,角色是 USER\r\n    @Override\r\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\r\n    \t\tauth\r\n                .inMemoryAuthentication()\r\n                .withUser(\"admin\").password(\"admin\").roles(\"USER\")\r\n                .and()\r\n                .withUser(\"abel\").password(\"abel\").roles(\"USER\");\r\n    }\r\n    //5忽略静态资源的拦截\r\n    @Override\r\n    public void configure(WebSecurity web) throws Exception {\r\n        web.ignoring().antMatchers(\"/resources/static/**\");\r\n    }\r\n\r\n}"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/config/WebSocketConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.messaging.simp.config.MessageBrokerRegistry;\nimport org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;\nimport org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;\nimport org.springframework.web.socket.config.annotation.StompEndpointRegistry;\n\n/**\n * Created by yangyibo on 16/12/29.\n */\n@Configuration\n@EnableWebSocketMessageBroker\n//通过EnableWebSocketMessageBroker 开启使用STOMP协议来传输基于代理(message broker)的消息,此时浏览器支持使用@MessageMapping 就像支持@RequestMapping一样。\npublic class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{\n\n\n    @Override\n    public void registerStompEndpoints(StompEndpointRegistry registry) { //endPoint 注册协议节点,并映射指定的URl\n\n        //注册一个Stomp 协议的endpoint,并指定 SockJS协议\n        registry.addEndpoint(\"/endpointWisely\").withSockJS();\n\n        //注册一个名字为\"endpointChat\" 的endpoint,并指定 SockJS协议。   点对点-用\n        registry.addEndpoint(\"/endpointChat\").withSockJS();\n    }\n\n\n    @Override\n    public void configureMessageBroker(MessageBrokerRegistry registry) {//配置消息代理(message broker)\n        //广播式应配置一个/topic 消息代理\n        registry.enableSimpleBroker(\"/topic\");\n\n        //点对点式增加一个/queue 消息代理\n        registry.enableSimpleBroker(\"/queue\",\"/topic\");\n\n    }\n}\n"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/controller/WebSocketController.java",
    "content": "package com.us.example.controller;\n\n\n\nimport com.us.example.bean.Message;\nimport com.us.example.bean.Response;\nimport com.us.example.service.WebSocketService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.messaging.handler.annotation.MessageMapping;\nimport org.springframework.messaging.handler.annotation.SendTo;\nimport org.springframework.messaging.simp.SimpMessagingTemplate;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.security.Principal;\n\n/**\n * Created by yangyibo on 16/12/29.\n *\n */\n@CrossOrigin\n@Controller\npublic class WebSocketController {\n    @Autowired\n    private WebSocketService ws;\n    @Autowired\n    private SimpMessagingTemplate messagingTemplate;\n\n\n    @RequestMapping(value = \"/login\")\n    public String login(){\n        return  \"login\";\n    }\n    @RequestMapping(value = \"/ws\")\n    public String ws(){\n        return  \"ws\";\n    }\n    @RequestMapping(value = \"/chat\")\n    public String chat(){\n        return  \"chat\";\n    }\n    //http://localhost:8080/ws\n    @MessageMapping(\"/welcome\")//浏览器发送请求通过@messageMapping 映射/welcome 这个地址。\n    @SendTo(\"/topic/getResponse\")//服务器端有消息时,会订阅@SendTo 中的路径的浏览器发送消息。\n    public Response say(Message message) throws Exception {\n        Thread.sleep(1000);\n        return new Response(\"Welcome, \" + message.getName() + \"!\");\n    }\n\n    //http://localhost:8080/Welcome1\n    @RequestMapping(\"/Welcome1\")\n    @ResponseBody\n    public String say2()throws Exception\n    {\n        ws.sendMessage();\n        return \"is ok\";\n    }\n\n    @MessageMapping(\"/chat\")\n    //在springmvc 中可以直接获得principal,principal 中包含当前用户的信息\n    public void handleChat(Principal principal, Message message) {\n\n        /**\n         * 此处是一段硬编码。如果发送人是wyf 则发送给 wisely 如果发送人是wisely 就发送给 wyf。\n         * 通过当前用户,然后查找消息,如果查找到未读消息,则发送给当前用户。\n         */\n        if (principal.getName().equals(\"admin\")) {\n            //通过convertAndSendToUser 向用户发送信息,\n            // 第一个参数是接收消息的用户,第二个参数是浏览器订阅的地址,第三个参数是消息本身\n\n            messagingTemplate.convertAndSendToUser(\"abel\",\n                    \"/queue/notifications\", principal.getName() + \"-send:\"\n                            + message.getName());\n            /**\n             * 72 行操作相等于 \n             * messagingTemplate.convertAndSend(\"/user/abel/queue/notifications\",principal.getName() + \"-send:\"\n             + message.getName());\n             */\n        } else {\n            messagingTemplate.convertAndSendToUser(\"admin\",\n                    \"/queue/notifications\", principal.getName() + \"-send:\"\n                            + message.getName());\n        }\n    }\n}\n"
  },
  {
    "path": "springWebSocket/src/main/java/com/us/example/service/WebSocketService.java",
    "content": "package com.us.example.service;\n\n/**\n * Created by yangyibo on 17/1/12.\n */\n\nimport com.us.example.bean.Response;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.messaging.simp.SimpMessagingTemplate;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class WebSocketService {\n\n    @Autowired\n    //使用SimpMessagingTemplate 向浏览器发送消息\n    private SimpMessagingTemplate template;\n\n    public void sendMessage() throws Exception{\n        for(int i=0;i<10;i++)\n        {\n            Thread.sleep(1000);\n            template.convertAndSend(\"/topic/getResponse\",new Response(\"Welcome,yangyibo !\"+i));\n            System.out.println(\"----------------------yangyibo\"+i);\n        }\n    }\n\n}\n"
  },
  {
    "path": "springWebSocket/src/main/resources/application.properties",
    "content": "server.port=8090\n"
  },
  {
    "path": "springWebSocket/src/main/resources/static/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v1.6.1\n * http://jquery.com/\n *\n * Copyright 2011, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2011, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Thu May 12 15:04:36 2011 -0400\n */\n(function( window, undefined ) {\n\n// Use the correct document accordingly with window argument (sandbox)\nvar document = window.document,\n\tnavigator = window.navigator,\n\tlocation = window.location;\nvar jQuery = (function() {\n\n// Define a local copy of jQuery\nvar jQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\treturn new jQuery.fn.init( selector, context, rootjQuery );\n\t},\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$,\n\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// A simple way to check for HTML strings or ID strings\n\t// (both of which we optimize for)\n\tquickExpr = /^(?:[^<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,\n\n\t// Check if a string has a non-whitespace character in it\n\trnotwhite = /\\S/,\n\n\t// Used for trimming whitespace\n\ttrimLeft = /^\\s+/,\n\ttrimRight = /\\s+$/,\n\n\t// Check for digits\n\trdigit = /\\d/,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n\n\t// JSON RegExp\n\trvalidchars = /^[\\],:{}\\s]*$/,\n\trvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,\n\trvalidtokens = /\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,\n\trvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\n\t// Useragent RegExp\n\trwebkit = /(webkit)[ \\/]([\\w.]+)/,\n\tropera = /(opera)(?:.*version)?[ \\/]([\\w.]+)/,\n\trmsie = /(msie) ([\\w.]+)/,\n\trmozilla = /(mozilla)(?:.*? rv:([\\w.]+))?/,\n\n\t// Keep a UserAgent string for use with jQuery.browser\n\tuserAgent = navigator.userAgent,\n\n\t// For matching the engine and version of the browser\n\tbrowserMatch,\n\n\t// The deferred used on DOM ready\n\treadyList,\n\n\t// The ready event handler\n\tDOMContentLoaded,\n\n\t// Save a reference to some core methods\n\ttoString = Object.prototype.toString,\n\thasOwn = Object.prototype.hasOwnProperty,\n\tpush = Array.prototype.push,\n\tslice = Array.prototype.slice,\n\ttrim = String.prototype.trim,\n\tindexOf = Array.prototype.indexOf,\n\n\t// [[Class]] -> type pairs\n\tclass2type = {};\n\njQuery.fn = jQuery.prototype = {\n\tconstructor: jQuery,\n\tinit: function( selector, context, rootjQuery ) {\n\t\tvar match, elem, ret, doc;\n\n\t\t// Handle $(\"\"), $(null), or $(undefined)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle $(DOMElement)\n\t\tif ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\t\t}\n\n\t\t// The body element only exists once, optimize finding it\n\t\tif ( selector === \"body\" && !context && document.body ) {\n\t\t\tthis.context = document;\n\t\t\tthis[0] = document.body;\n\t\t\tthis.selector = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\t// Are we dealing with HTML string or an ID?\n\t\t\tif ( selector.charAt(0) === \"<\" && selector.charAt( selector.length - 1 ) === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = quickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Verify a match, and that no context was specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\t\t\t\t\tdoc = (context ? context.ownerDocument || context : document);\n\n\t\t\t\t\t// If a single string is passed in and it's a single tag\n\t\t\t\t\t// just do a createElement and skip the rest\n\t\t\t\t\tret = rsingleTag.exec( selector );\n\n\t\t\t\t\tif ( ret ) {\n\t\t\t\t\t\tif ( jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\t\tselector = [ document.createElement( ret[1] ) ];\n\t\t\t\t\t\t\tjQuery.fn.attr.call( selector, context, true );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tselector = [ doc.createElement( ret[1] ) ];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = jQuery.buildFragment( [ match[1] ], [ doc ] );\n\t\t\t\t\t\tselector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.merge( this, selector );\n\n\t\t\t\t// HANDLE: $(\"#id\")\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn (context || rootjQuery).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn rootjQuery.ready( selector );\n\t\t}\n\n\t\tif (selector.selector !== undefined) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t},\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The current version of jQuery being used\n\tjquery: \"1.6.1\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn slice.call( this, 0 );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num == null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this[ this.length + num ] : this[ num ] );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems, name, selector ) {\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = this.constructor();\n\n\t\tif ( jQuery.isArray( elems ) ) {\n\t\t\tpush.apply( ret, elems );\n\n\t\t} else {\n\t\t\tjQuery.merge( ret, elems );\n\t\t}\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\tret.context = this.context;\n\n\t\tif ( name === \"find\" ) {\n\t\t\tret.selector = this.selector + (this.selector ? \" \" : \"\") + selector;\n\t\t} else if ( name ) {\n\t\t\tret.selector = this.selector + \".\" + name + \"(\" + selector + \")\";\n\t\t}\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tready: function( fn ) {\n\t\t// Attach the listeners\n\t\tjQuery.bindReady();\n\n\t\t// Add the callback\n\t\treadyList.done( fn );\n\n\t\treturn this;\n\t},\n\n\teq: function( i ) {\n\t\treturn i === -1 ?\n\t\t\tthis.slice( i ) :\n\t\t\tthis.slice( i, +i + 1 );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ),\n\t\t\t\"slice\", slice.call(arguments).join(\",\") );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\tnoConflict: function( deep ) {\n\t\tif ( window.$ === jQuery ) {\n\t\t\twindow.$ = _$;\n\t\t}\n\n\t\tif ( deep && window.jQuery === jQuery ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\t\t// Either a released hold or an DOMready/load event and not yet ready\n\t\tif ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {\n\t\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\t\tif ( !document.body ) {\n\t\t\t\treturn setTimeout( jQuery.ready, 1 );\n\t\t\t}\n\n\t\t\t// Remember that the DOM is ready\n\t\t\tjQuery.isReady = true;\n\n\t\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If there are functions bound, to execute\n\t\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t\t// Trigger any bound ready events\n\t\t\tif ( jQuery.fn.trigger ) {\n\t\t\t\tjQuery( document ).trigger( \"ready\" ).unbind( \"ready\" );\n\t\t\t}\n\t\t}\n\t},\n\n\tbindReady: function() {\n\t\tif ( readyList ) {\n\t\t\treturn;\n\t\t}\n\n\t\treadyList = jQuery._Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the\n\t\t// browser event has already occurred.\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\treturn setTimeout( jQuery.ready, 1 );\n\t\t}\n\n\t\t// Mozilla, Opera and webkit nightlies currently support this event\n\t\tif ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", jQuery.ready, false );\n\n\t\t// If IE event model is used\n\t\t} else if ( document.attachEvent ) {\n\t\t\t// ensure firing before onload,\n\t\t\t// maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", DOMContentLoaded );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", jQuery.ready );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar toplevel = false;\n\n\t\t\ttry {\n\t\t\t\ttoplevel = window.frameElement == null;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( document.documentElement.doScroll && toplevel ) {\n\t\t\t\tdoScrollCheck();\n\t\t\t}\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray || function( obj ) {\n\t\treturn jQuery.type(obj) === \"array\";\n\t},\n\n\t// A crude way of determining if an object is a window\n\tisWindow: function( obj ) {\n\t\treturn obj && typeof obj === \"object\" && \"setInterval\" in obj;\n\t},\n\n\tisNaN: function( obj ) {\n\t\treturn obj == null || !rdigit.test( obj ) || isNaN( obj );\n\t},\n\n\ttype: function( obj ) {\n\t\treturn obj == null ?\n\t\t\tString( obj ) :\n\t\t\tclass2type[ toString.call(obj) ] || \"object\";\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Not own constructor property must be Object\n\t\tif ( obj.constructor &&\n\t\t\t!hasOwn.call(obj, \"constructor\") &&\n\t\t\t!hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || hasOwn.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tfor ( var name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\terror: function( msg ) {\n\t\tthrow msg;\n\t},\n\n\tparseJSON: function( data ) {\n\t\tif ( typeof data !== \"string\" || !data ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Make sure leading/trailing whitespace is removed (IE can't handle it)\n\t\tdata = jQuery.trim( data );\n\n\t\t// Attempt to parse using the native JSON parser first\n\t\tif ( window.JSON && window.JSON.parse ) {\n\t\t\treturn window.JSON.parse( data );\n\t\t}\n\n\t\t// Make sure the incoming data is actual JSON\n\t\t// Logic borrowed from http://json.org/json2.js\n\t\tif ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n\t\t\t.replace( rvalidtokens, \"]\" )\n\t\t\t.replace( rvalidbraces, \"\")) ) {\n\n\t\t\treturn (new Function( \"return \" + data ))();\n\n\t\t}\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t},\n\n\t// Cross-browser xml parsing\n\t// (xml & tmp used internally)\n\tparseXML: function( data , xml , tmp ) {\n\n\t\tif ( window.DOMParser ) { // Standard\n\t\t\ttmp = new DOMParser();\n\t\t\txml = tmp.parseFromString( data , \"text/xml\" );\n\t\t} else { // IE\n\t\t\txml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n\t\t\txml.async = \"false\";\n\t\t\txml.loadXML( data );\n\t\t}\n\n\t\ttmp = xml.documentElement;\n\n\t\tif ( ! tmp || ! tmp.nodeName || tmp.nodeName === \"parsererror\" ) {\n\t\t\tjQuery.error( \"Invalid XML: \" + data );\n\t\t}\n\n\t\treturn xml;\n\t},\n\n\tnoop: function() {},\n\n\t// Evaluates a script in a global context\n\t// Workarounds based on findings by Jim Driscoll\n\t// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n\tglobalEval: function( data ) {\n\t\tif ( data && rnotwhite.test( data ) ) {\n\t\t\t// We use execScript on Internet Explorer\n\t\t\t// We use an anonymous function so that context is window\n\t\t\t// rather than jQuery in Firefox\n\t\t\t( window.execScript || function( data ) {\n\t\t\t\twindow[ \"eval\" ].call( window, data );\n\t\t\t} )( data );\n\t\t}\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( object, callback, args ) {\n\t\tvar name, i = 0,\n\t\t\tlength = object.length,\n\t\t\tisObj = length === undefined || jQuery.isFunction( object );\n\n\t\tif ( args ) {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.apply( object[ name ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( ; i < length; ) {\n\t\t\t\t\tif ( callback.apply( object[ i++ ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( ; i < length; ) {\n\t\t\t\t\tif ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn object;\n\t},\n\n\t// Use native String.trim function wherever possible\n\ttrim: trim ?\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\ttrim.call( text );\n\t\t} :\n\n\t\t// Otherwise use our own trimming functionality\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\ttext.toString().replace( trimLeft, \"\" ).replace( trimRight, \"\" );\n\t\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( array, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( array != null ) {\n\t\t\t// The window, strings (and functions) also have 'length'\n\t\t\t// The extra typeof function check is to prevent crashes\n\t\t\t// in Safari 2 (See: #3039)\n\t\t\t// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930\n\t\t\tvar type = jQuery.type( array );\n\n\t\t\tif ( array.length == null || type === \"string\" || type === \"function\" || type === \"regexp\" || jQuery.isWindow( array ) ) {\n\t\t\t\tpush.call( ret, array );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( ret, array );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, array ) {\n\n\t\tif ( indexOf ) {\n\t\t\treturn indexOf.call( array, elem );\n\t\t}\n\n\t\tfor ( var i = 0, length = array.length; i < length; i++ ) {\n\t\t\tif ( array[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar i = first.length,\n\t\t\tj = 0;\n\n\t\tif ( typeof second.length === \"number\" ) {\n\t\t\tfor ( var l = second.length; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar ret = [], retVal;\n\t\tinv = !!inv;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n\t\t\tretVal = !!callback( elems[ i ], i );\n\t\t\tif ( inv !== retVal ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value, key, ret = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\t// jquery objects are treated as arrays\n\t\t\tisArray = elems instanceof jQuery || length !== undefined && typeof length === \"number\" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;\n\n\t\t// Go through the array, translating each of the items to their\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( key in elems ) {\n\t\t\t\tvalue = callback( elems[ key ], key, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn ret.concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tif ( typeof context === \"string\" ) {\n\t\t\tvar tmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\tvar args = slice.call( arguments, 2 ),\n\t\t\tproxy = function() {\n\t\t\t\treturn fn.apply( context, args.concat( slice.call( arguments ) ) );\n\t\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\t// Mutifunctional method to get and set values to a collection\n\t// The value/s can be optionally by executed if its a function\n\taccess: function( elems, key, value, exec, fn, pass ) {\n\t\tvar length = elems.length;\n\n\t\t// Setting many attributes\n\t\tif ( typeof key === \"object\" ) {\n\t\t\tfor ( var k in key ) {\n\t\t\t\tjQuery.access( elems, k, key[k], exec, fn, value );\n\t\t\t}\n\t\t\treturn elems;\n\t\t}\n\n\t\t// Setting one attribute\n\t\tif ( value !== undefined ) {\n\t\t\t// Optionally, function values get executed if exec is true\n\t\t\texec = !pass && exec && jQuery.isFunction(value);\n\n\t\t\tfor ( var i = 0; i < length; i++ ) {\n\t\t\t\tfn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n\t\t\t}\n\n\t\t\treturn elems;\n\t\t}\n\n\t\t// Getting an attribute\n\t\treturn length ? fn( elems[0], key ) : undefined;\n\t},\n\n\tnow: function() {\n\t\treturn (new Date()).getTime();\n\t},\n\n\t// Use of jQuery.browser is frowned upon.\n\t// More details: http://docs.jquery.com/Utilities/jQuery.browser\n\tuaMatch: function( ua ) {\n\t\tua = ua.toLowerCase();\n\n\t\tvar match = rwebkit.exec( ua ) ||\n\t\t\tropera.exec( ua ) ||\n\t\t\trmsie.exec( ua ) ||\n\t\t\tua.indexOf(\"compatible\") < 0 && rmozilla.exec( ua ) ||\n\t\t\t[];\n\n\t\treturn { browser: match[1] || \"\", version: match[2] || \"0\" };\n\t},\n\n\tsub: function() {\n\t\tfunction jQuerySub( selector, context ) {\n\t\t\treturn new jQuerySub.fn.init( selector, context );\n\t\t}\n\t\tjQuery.extend( true, jQuerySub, this );\n\t\tjQuerySub.superclass = this;\n\t\tjQuerySub.fn = jQuerySub.prototype = this();\n\t\tjQuerySub.fn.constructor = jQuerySub;\n\t\tjQuerySub.sub = this.sub;\n\t\tjQuerySub.fn.init = function init( selector, context ) {\n\t\t\tif ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {\n\t\t\t\tcontext = jQuerySub( context );\n\t\t\t}\n\n\t\t\treturn jQuery.fn.init.call( this, selector, context, rootjQuerySub );\n\t\t};\n\t\tjQuerySub.fn.init.prototype = jQuerySub.fn;\n\t\tvar rootjQuerySub = jQuerySub(document);\n\t\treturn jQuerySub;\n\t},\n\n\tbrowser: {}\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nbrowserMatch = jQuery.uaMatch( userAgent );\nif ( browserMatch.browser ) {\n\tjQuery.browser[ browserMatch.browser ] = true;\n\tjQuery.browser.version = browserMatch.version;\n}\n\n// Deprecated, use jQuery.browser.webkit instead\nif ( jQuery.browser.webkit ) {\n\tjQuery.browser.safari = true;\n}\n\n// IE doesn't match non-breaking spaces with \\s\nif ( rnotwhite.test( \"\\xA0\" ) ) {\n\ttrimLeft = /^[\\s\\xA0]+/;\n\ttrimRight = /[\\s\\xA0]+$/;\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\nif ( document.addEventListener ) {\n\tDOMContentLoaded = function() {\n\t\tdocument.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\t\tjQuery.ready();\n\t};\n\n} else if ( document.attachEvent ) {\n\tDOMContentLoaded = function() {\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\tdocument.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n\t\t\tjQuery.ready();\n\t\t}\n\t};\n}\n\n// The DOM ready check for Internet Explorer\nfunction doScrollCheck() {\n\tif ( jQuery.isReady ) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// If IE is used, use the trick by Diego Perini\n\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\tdocument.documentElement.doScroll(\"left\");\n\t} catch(e) {\n\t\tsetTimeout( doScrollCheck, 1 );\n\t\treturn;\n\t}\n\n\t// and execute any waiting functions\n\tjQuery.ready();\n}\n\n// Expose jQuery to the global object\nreturn jQuery;\n\n})();\n\n\nvar // Promise methods\n\tpromiseMethods = \"done fail isResolved isRejected promise then always pipe\".split( \" \" ),\n\t// Static reference to slice\n\tsliceDeferred = [].slice;\n\njQuery.extend({\n\t// Create a simple deferred (one callbacks list)\n\t_Deferred: function() {\n\t\tvar // callbacks list\n\t\t\tcallbacks = [],\n\t\t\t// stored [ context , args ]\n\t\t\tfired,\n\t\t\t// to avoid firing when already doing so\n\t\t\tfiring,\n\t\t\t// flag to know if the deferred has been cancelled\n\t\t\tcancelled,\n\t\t\t// the deferred itself\n\t\t\tdeferred  = {\n\n\t\t\t\t// done( f1, f2, ...)\n\t\t\t\tdone: function() {\n\t\t\t\t\tif ( !cancelled ) {\n\t\t\t\t\t\tvar args = arguments,\n\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\telem,\n\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t_fired;\n\t\t\t\t\t\tif ( fired ) {\n\t\t\t\t\t\t\t_fired = fired;\n\t\t\t\t\t\t\tfired = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor ( i = 0, length = args.length; i < length; i++ ) {\n\t\t\t\t\t\t\telem = args[ i ];\n\t\t\t\t\t\t\ttype = jQuery.type( elem );\n\t\t\t\t\t\t\tif ( type === \"array\" ) {\n\t\t\t\t\t\t\t\tdeferred.done.apply( deferred, elem );\n\t\t\t\t\t\t\t} else if ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tcallbacks.push( elem );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( _fired ) {\n\t\t\t\t\t\t\tdeferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// resolve with given context and args\n\t\t\t\tresolveWith: function( context, args ) {\n\t\t\t\t\tif ( !cancelled && !fired && !firing ) {\n\t\t\t\t\t\t// make sure args are available (#8421)\n\t\t\t\t\t\targs = args || [];\n\t\t\t\t\t\tfiring = 1;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\twhile( callbacks[ 0 ] ) {\n\t\t\t\t\t\t\t\tcallbacks.shift().apply( context, args );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tfired = [ context, args ];\n\t\t\t\t\t\t\tfiring = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// resolve with this as context and given arguments\n\t\t\t\tresolve: function() {\n\t\t\t\t\tdeferred.resolveWith( this, arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Has this deferred been resolved?\n\t\t\t\tisResolved: function() {\n\t\t\t\t\treturn !!( firing || fired );\n\t\t\t\t},\n\n\t\t\t\t// Cancel\n\t\t\t\tcancel: function() {\n\t\t\t\t\tcancelled = 1;\n\t\t\t\t\tcallbacks = [];\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\treturn deferred;\n\t},\n\n\t// Full fledged deferred (two callbacks list)\n\tDeferred: function( func ) {\n\t\tvar deferred = jQuery._Deferred(),\n\t\t\tfailDeferred = jQuery._Deferred(),\n\t\t\tpromise;\n\t\t// Add errorDeferred methods, then and promise\n\t\tjQuery.extend( deferred, {\n\t\t\tthen: function( doneCallbacks, failCallbacks ) {\n\t\t\t\tdeferred.done( doneCallbacks ).fail( failCallbacks );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\talways: function() {\n\t\t\t\treturn deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );\n\t\t\t},\n\t\t\tfail: failDeferred.done,\n\t\t\trejectWith: failDeferred.resolveWith,\n\t\t\treject: failDeferred.resolve,\n\t\t\tisRejected: failDeferred.isResolved,\n\t\t\tpipe: function( fnDone, fnFail ) {\n\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\tjQuery.each( {\n\t\t\t\t\t\tdone: [ fnDone, \"resolve\" ],\n\t\t\t\t\t\tfail: [ fnFail, \"reject\" ]\n\t\t\t\t\t}, function( handler, data ) {\n\t\t\t\t\t\tvar fn = data[ 0 ],\n\t\t\t\t\t\t\taction = data[ 1 ],\n\t\t\t\t\t\t\treturned;\n\t\t\t\t\t\tif ( jQuery.isFunction( fn ) ) {\n\t\t\t\t\t\t\tdeferred[ handler ](function() {\n\t\t\t\t\t\t\t\treturned = fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise().then( newDefer.resolve, newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ action ]( returned );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdeferred[ handler ]( newDefer[ action ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}).promise();\n\t\t\t},\n\t\t\t// Get a promise for this deferred\n\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\tpromise: function( obj ) {\n\t\t\t\tif ( obj == null ) {\n\t\t\t\t\tif ( promise ) {\n\t\t\t\t\t\treturn promise;\n\t\t\t\t\t}\n\t\t\t\t\tpromise = obj = {};\n\t\t\t\t}\n\t\t\t\tvar i = promiseMethods.length;\n\t\t\t\twhile( i-- ) {\n\t\t\t\t\tobj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];\n\t\t\t\t}\n\t\t\t\treturn obj;\n\t\t\t}\n\t\t});\n\t\t// Make sure only one callback list will be used\n\t\tdeferred.done( failDeferred.cancel ).fail( deferred.cancel );\n\t\t// Unexpose cancel\n\t\tdelete deferred.cancel;\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( firstParam ) {\n\t\tvar args = arguments,\n\t\t\ti = 0,\n\t\t\tlength = args.length,\n\t\t\tcount = length,\n\t\t\tdeferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?\n\t\t\t\tfirstParam :\n\t\t\t\tjQuery.Deferred();\n\t\tfunction resolveFunc( i ) {\n\t\t\treturn function( value ) {\n\t\t\t\targs[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\t// Strange bug in FF4:\n\t\t\t\t\t// Values changed onto the arguments object sometimes end up as undefined values\n\t\t\t\t\t// outside the $.when method. Cloning the object into a fresh array solves the issue\n\t\t\t\t\tdeferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tif ( length > 1 ) {\n\t\t\tfor( ; i < length; i++ ) {\n\t\t\t\tif ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {\n\t\t\t\t\targs[ i ].promise().then( resolveFunc(i), deferred.reject );\n\t\t\t\t} else {\n\t\t\t\t\t--count;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( !count ) {\n\t\t\t\tdeferred.resolveWith( deferred, args );\n\t\t\t}\n\t\t} else if ( deferred !== firstParam ) {\n\t\t\tdeferred.resolveWith( deferred, length ? [ firstParam ] : [] );\n\t\t}\n\t\treturn deferred.promise();\n\t}\n});\n\n\n\njQuery.support = (function() {\n\n\tvar div = document.createElement( \"div\" ),\n\t\tdocumentElement = document.documentElement,\n\t\tall,\n\t\ta,\n\t\tselect,\n\t\topt,\n\t\tinput,\n\t\tmarginDiv,\n\t\tsupport,\n\t\tfragment,\n\t\tbody,\n\t\tbodyStyle,\n\t\ttds,\n\t\tevents,\n\t\teventName,\n\t\ti,\n\t\tisSupported;\n\n\t// Preliminary tests\n\tdiv.setAttribute(\"className\", \"t\");\n\tdiv.innerHTML = \"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";\n\n\tall = div.getElementsByTagName( \"*\" );\n\ta = div.getElementsByTagName( \"a\" )[ 0 ];\n\n\t// Can't get basic test support\n\tif ( !all || !all.length || !a ) {\n\t\treturn {};\n\t}\n\n\t// First batch of supports tests\n\tselect = document.createElement( \"select\" );\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName( \"input\" )[ 0 ];\n\n\tsupport = {\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: ( div.firstChild.nodeType === 3 ),\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName( \"tbody\" ).length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName( \"link\" ).length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText instead)\n\t\tstyle: /top/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: ( a.getAttribute( \"href\" ) === \"/a\" ),\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.55$/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Make sure that if no value is specified for a checkbox\n\t\t// that it defaults to \"on\".\n\t\t// (WebKit defaults to \"\" instead)\n\t\tcheckOn: ( input.value === \"on\" ),\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: opt.selected,\n\n\t\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\t\tgetSetAttribute: div.className !== \"t\",\n\n\t\t// Will be defined later\n\t\tsubmitBubbles: true,\n\t\tchangeBubbles: true,\n\t\tfocusinBubbles: false,\n\t\tdeleteExpando: true,\n\t\tnoCloneEvent: true,\n\t\tinlineBlockNeedsLayout: false,\n\t\tshrinkWrapBlocks: false,\n\t\treliableMarginRight: true\n\t};\n\n\t// Make sure checked status is properly cloned\n\tinput.checked = true;\n\tsupport.noCloneChecked = input.cloneNode( true ).checked;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Test to see if it's possible to delete an expando from an element\n\t// Fails in Internet Explorer\n\ttry {\n\t\tdelete div.test;\n\t} catch( e ) {\n\t\tsupport.deleteExpando = false;\n\t}\n\n\tif ( !div.addEventListener && div.attachEvent && div.fireEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function click() {\n\t\t\t// Cloning a node shouldn't copy over any\n\t\t\t// bound event handlers (IE does this)\n\t\t\tsupport.noCloneEvent = false;\n\t\t\tdiv.detachEvent( \"onclick\", click );\n\t\t});\n\t\tdiv.cloneNode( true ).fireEvent( \"onclick\" );\n\t}\n\n\t// Check if a radio maintains it's value\n\t// after being appended to the DOM\n\tinput = document.createElement(\"input\");\n\tinput.value = \"t\";\n\tinput.setAttribute(\"type\", \"radio\");\n\tsupport.radioValue = input.value === \"t\";\n\n\tinput.setAttribute(\"checked\", \"checked\");\n\tdiv.appendChild( input );\n\tfragment = document.createDocumentFragment();\n\tfragment.appendChild( div.firstChild );\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\tdiv.innerHTML = \"\";\n\n\t// Figure out if the W3C box model works as expected\n\tdiv.style.width = div.style.paddingLeft = \"1px\";\n\n\t// We use our own, invisible, body\n\tbody = document.createElement( \"body\" );\n\tbodyStyle = {\n\t\tvisibility: \"hidden\",\n\t\twidth: 0,\n\t\theight: 0,\n\t\tborder: 0,\n\t\tmargin: 0,\n\t\t// Set background to avoid IE crashes when removing (#9028)\n\t\tbackground: \"none\"\n\t};\n\tfor ( i in bodyStyle ) {\n\t\tbody.style[ i ] = bodyStyle[ i ];\n\t}\n\tbody.appendChild( div );\n\tdocumentElement.insertBefore( body, documentElement.firstChild );\n\n\t// Check if a disconnected checkbox will retain its checked\n\t// value of true after appended to the DOM (IE6/7)\n\tsupport.appendChecked = input.checked;\n\n\tsupport.boxModel = div.offsetWidth === 2;\n\n\tif ( \"zoom\" in div.style ) {\n\t\t// Check if natively block-level elements act like inline-block\n\t\t// elements when setting their display to 'inline' and giving\n\t\t// them layout\n\t\t// (IE < 8 does this)\n\t\tdiv.style.display = \"inline\";\n\t\tdiv.style.zoom = 1;\n\t\tsupport.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );\n\n\t\t// Check if elements with layout shrink-wrap their children\n\t\t// (IE 6 does this)\n\t\tdiv.style.display = \"\";\n\t\tdiv.innerHTML = \"<div style='width:4px;'></div>\";\n\t\tsupport.shrinkWrapBlocks = ( div.offsetWidth !== 2 );\n\t}\n\n\tdiv.innerHTML = \"<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>\";\n\ttds = div.getElementsByTagName( \"td\" );\n\n\t// Check if table cells still have offsetWidth/Height when they are set\n\t// to display:none and there are still other visible table cells in a\n\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t// determining if an element has been hidden directly using\n\t// display:none (it is still safe to use offsets if a parent element is\n\t// hidden; don safety goggles and see bug #4512 for more information).\n\t// (only IE 8 fails this test)\n\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\ttds[ 0 ].style.display = \"\";\n\ttds[ 1 ].style.display = \"none\";\n\n\t// Check if empty table cells still have offsetWidth/Height\n\t// (IE < 8 fail this test)\n\tsupport.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\tdiv.innerHTML = \"\";\n\n\t// Check if div with explicit width and no margin-right incorrectly\n\t// gets computed margin-right based on width of container. For more\n\t// info see bug #3333\n\t// Fails in WebKit before Feb 2011 nightlies\n\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\tif ( document.defaultView && document.defaultView.getComputedStyle ) {\n\t\tmarginDiv = document.createElement( \"div\" );\n\t\tmarginDiv.style.width = \"0\";\n\t\tmarginDiv.style.marginRight = \"0\";\n\t\tdiv.appendChild( marginDiv );\n\t\tsupport.reliableMarginRight =\n\t\t\t( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;\n\t}\n\n\t// Remove the body element we added\n\tbody.innerHTML = \"\";\n\tdocumentElement.removeChild( body );\n\n\t// Technique from Juriy Zaytsev\n\t// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/\n\t// We only care about the case where non-standard event systems\n\t// are used, namely in IE. Short-circuiting here helps us to\n\t// avoid an eval call (in setAttribute) which can cause CSP\n\t// to go haywire. See: https://developer.mozilla.org/en/Security/CSP\n\tif ( div.attachEvent ) {\n\t\tfor( i in {\n\t\t\tsubmit: 1,\n\t\t\tchange: 1,\n\t\t\tfocusin: 1\n\t\t} ) {\n\t\t\teventName = \"on\" + i;\n\t\t\tisSupported = ( eventName in div );\n\t\t\tif ( !isSupported ) {\n\t\t\t\tdiv.setAttribute( eventName, \"return;\" );\n\t\t\t\tisSupported = ( typeof div[ eventName ] === \"function\" );\n\t\t\t}\n\t\t\tsupport[ i + \"Bubbles\" ] = isSupported;\n\t\t}\n\t}\n\n\treturn support;\n})();\n\n// Keep track of boxModel\njQuery.boxModel = jQuery.support.boxModel;\n\n\n\n\nvar rbrace = /^(?:\\{.*\\}|\\[.*\\])$/,\n\trmultiDash = /([a-z])([A-Z])/g;\n\njQuery.extend({\n\tcache: {},\n\n\t// Please use with caution\n\tuuid: 0,\n\n\t// Unique for each copy of jQuery on the page\n\t// Non-digits removed to match rinlinejQuery\n\texpando: \"jQuery\" + ( jQuery.fn.jquery + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t// Ban all objects except for Flash (which handle expandos)\n\t\t\"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n\t\t\"applet\": true\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data, pvt /* Internal Use Only */ ) {\n\t\tif ( !jQuery.acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar internalKey = jQuery.expando, getByName = typeof name === \"string\", thisCache,\n\n\t\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t\t// can't GC object references properly across the DOM-JS boundary\n\t\t\tisNode = elem.nodeType,\n\n\t\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t\t// attached directly to the object so GC can occur automatically\n\t\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\t\tid = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;\n\n\t\t// Avoid doing any more work than we need to when trying to get data on an\n\t\t// object that has no data at all\n\t\tif ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !id ) {\n\t\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t\t// ends up in the global cache\n\t\t\tif ( isNode ) {\n\t\t\t\telem[ jQuery.expando ] = id = ++jQuery.uuid;\n\t\t\t} else {\n\t\t\t\tid = jQuery.expando;\n\t\t\t}\n\t\t}\n\n\t\tif ( !cache[ id ] ) {\n\t\t\tcache[ id ] = {};\n\n\t\t\t// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery\n\t\t\t// metadata on plain JS objects when the object is serialized using\n\t\t\t// JSON.stringify\n\t\t\tif ( !isNode ) {\n\t\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t\t}\n\t\t}\n\n\t\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t\t// shallow copied over onto the existing cache\n\t\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\t\tif ( pvt ) {\n\t\t\t\tcache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);\n\t\t\t} else {\n\t\t\t\tcache[ id ] = jQuery.extend(cache[ id ], name);\n\t\t\t}\n\t\t}\n\n\t\tthisCache = cache[ id ];\n\n\t\t// Internal jQuery data is stored in a separate object inside the object's data\n\t\t// cache in order to avoid key collisions between internal data and user-defined\n\t\t// data\n\t\tif ( pvt ) {\n\t\t\tif ( !thisCache[ internalKey ] ) {\n\t\t\t\tthisCache[ internalKey ] = {};\n\t\t\t}\n\n\t\t\tthisCache = thisCache[ internalKey ];\n\t\t}\n\n\t\tif ( data !== undefined ) {\n\t\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t\t}\n\n\t\t// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should\n\t\t// not attempt to inspect the internal events object using jQuery.data, as this\n\t\t// internal data object is undocumented and subject to change.\n\t\tif ( name === \"events\" && !thisCache[name] ) {\n\t\t\treturn thisCache[ internalKey ] && thisCache[ internalKey ].events;\n\t\t}\n\n\t\treturn getByName ? thisCache[ jQuery.camelCase( name ) ] : thisCache;\n\t},\n\n\tremoveData: function( elem, name, pvt /* Internal Use Only */ ) {\n\t\tif ( !jQuery.acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar internalKey = jQuery.expando, isNode = elem.nodeType,\n\n\t\t\t// See jQuery.data for more information\n\t\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t\t// See jQuery.data for more information\n\t\t\tid = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n\t\t// If there is already no cache entry for this object, there is no\n\t\t// purpose in continuing\n\t\tif ( !cache[ id ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( name ) {\n\t\t\tvar thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];\n\n\t\t\tif ( thisCache ) {\n\t\t\t\tdelete thisCache[ name ];\n\n\t\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t\t// and let the cache object itself get destroyed\n\t\t\t\tif ( !isEmptyDataObject(thisCache) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// See jQuery.data for more information\n\t\tif ( pvt ) {\n\t\t\tdelete cache[ id ][ internalKey ];\n\n\t\t\t// Don't destroy the parent cache unless the internal data object\n\t\t\t// had been the only thing left in it\n\t\t\tif ( !isEmptyDataObject(cache[ id ]) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tvar internalCache = cache[ id ][ internalKey ];\n\n\t\t// Browsers that fail expando deletion also refuse to delete expandos on\n\t\t// the window, but it will allow it on all other JS objects; other browsers\n\t\t// don't care\n\t\tif ( jQuery.support.deleteExpando || cache != window ) {\n\t\t\tdelete cache[ id ];\n\t\t} else {\n\t\t\tcache[ id ] = null;\n\t\t}\n\n\t\t// We destroyed the entire user cache at once because it's faster than\n\t\t// iterating through each key, but we need to continue to persist internal\n\t\t// data if it existed\n\t\tif ( internalCache ) {\n\t\t\tcache[ id ] = {};\n\t\t\t// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery\n\t\t\t// metadata on plain JS objects when the object is serialized using\n\t\t\t// JSON.stringify\n\t\t\tif ( !isNode ) {\n\t\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t\t}\n\n\t\t\tcache[ id ][ internalKey ] = internalCache;\n\n\t\t// Otherwise, we need to eliminate the expando on the node to avoid\n\t\t// false lookups in the cache for entries that no longer exist\n\t\t} else if ( isNode ) {\n\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t// we must handle all of these cases\n\t\t\tif ( jQuery.support.deleteExpando ) {\n\t\t\t\tdelete elem[ jQuery.expando ];\n\t\t\t} else if ( elem.removeAttribute ) {\n\t\t\t\telem.removeAttribute( jQuery.expando );\n\t\t\t} else {\n\t\t\t\telem[ jQuery.expando ] = null;\n\t\t\t}\n\t\t}\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn jQuery.data( elem, name, data, true );\n\t},\n\n\t// A method for determining if a DOM node can handle the data expando\n\tacceptData: function( elem ) {\n\t\tif ( elem.nodeName ) {\n\t\t\tvar match = jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n\t\t\tif ( match ) {\n\t\t\t\treturn !(match === true || elem.getAttribute(\"classid\") !== match);\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar data = null;\n\n\t\tif ( typeof key === \"undefined\" ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( this[0] );\n\n\t\t\t\tif ( this[0].nodeType === 1 ) {\n\t\t\t    var attr = this[0].attributes, name;\n\t\t\t\t\tfor ( var i = 0, l = attr.length; i < l; i++ ) {\n\t\t\t\t\t\tname = attr[i].name;\n\n\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.substring(5) );\n\n\t\t\t\t\t\t\tdataAttr( this[0], name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t} else if ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\tvar parts = key.split(\".\");\n\t\tparts[1] = parts[1] ? \".\" + parts[1] : \"\";\n\n\t\tif ( value === undefined ) {\n\t\t\tdata = this.triggerHandler(\"getData\" + parts[1] + \"!\", [parts[0]]);\n\n\t\t\t// Try to fetch any internally stored data first\n\t\t\tif ( data === undefined && this.length ) {\n\t\t\t\tdata = jQuery.data( this[0], key );\n\t\t\t\tdata = dataAttr( this[0], key, data );\n\t\t\t}\n\n\t\t\treturn data === undefined && parts[1] ?\n\t\t\t\tthis.data( parts[0] ) :\n\t\t\t\tdata;\n\n\t\t} else {\n\t\t\treturn this.each(function() {\n\t\t\t\tvar $this = jQuery( this ),\n\t\t\t\t\targs = [ parts[0], value ];\n\n\t\t\t\t$this.triggerHandler( \"setData\" + parts[1] + \"!\", args );\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t\t$this.triggerHandler( \"changeData\" + parts[1] + \"!\", args );\n\t\t\t});\n\t\t}\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\n\nfunction dataAttr( elem, key, data ) {\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"$1-$2\" ).toLowerCase();\n\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\tdata === \"false\" ? false :\n\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t!jQuery.isNaN( data ) ? parseFloat( data ) :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tjQuery.data( elem, key, data );\n\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON\n// property to be considered empty objects; this property always exists in\n// order to make sure JSON.stringify does not expose internal metadata\nfunction isEmptyDataObject( obj ) {\n\tfor ( var name in obj ) {\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n\n\n\nfunction handleQueueMarkDefer( elem, type, src ) {\n\tvar deferDataKey = type + \"defer\",\n\t\tqueueDataKey = type + \"queue\",\n\t\tmarkDataKey = type + \"mark\",\n\t\tdefer = jQuery.data( elem, deferDataKey, undefined, true );\n\tif ( defer &&\n\t\t( src === \"queue\" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&\n\t\t( src === \"mark\" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {\n\t\t// Give room for hard-coded callbacks to fire first\n\t\t// and eventually mark/queue something else on the element\n\t\tsetTimeout( function() {\n\t\t\tif ( !jQuery.data( elem, queueDataKey, undefined, true ) &&\n\t\t\t\t!jQuery.data( elem, markDataKey, undefined, true ) ) {\n\t\t\t\tjQuery.removeData( elem, deferDataKey, true );\n\t\t\t\tdefer.resolve();\n\t\t\t}\n\t\t}, 0 );\n\t}\n}\n\njQuery.extend({\n\n\t_mark: function( elem, type ) {\n\t\tif ( elem ) {\n\t\t\ttype = (type || \"fx\") + \"mark\";\n\t\t\tjQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );\n\t\t}\n\t},\n\n\t_unmark: function( force, elem, type ) {\n\t\tif ( force !== true ) {\n\t\t\ttype = elem;\n\t\t\telem = force;\n\t\t\tforce = false;\n\t\t}\n\t\tif ( elem ) {\n\t\t\ttype = type || \"fx\";\n\t\t\tvar key = type + \"mark\",\n\t\t\t\tcount = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );\n\t\t\tif ( count ) {\n\t\t\t\tjQuery.data( elem, key, count, true );\n\t\t\t} else {\n\t\t\t\tjQuery.removeData( elem, key, true );\n\t\t\t\thandleQueueMarkDefer( elem, type, \"mark\" );\n\t\t\t}\n\t\t}\n\t},\n\n\tqueue: function( elem, type, data ) {\n\t\tif ( elem ) {\n\t\t\ttype = (type || \"fx\") + \"queue\";\n\t\t\tvar q = jQuery.data( elem, type, undefined, true );\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !q || jQuery.isArray(data) ) {\n\t\t\t\t\tq = jQuery.data( elem, type, jQuery.makeArray(data), true );\n\t\t\t\t} else {\n\t\t\t\t\tq.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn q || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tfn = queue.shift(),\n\t\t\tdefer;\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift(\"inprogress\");\n\t\t\t}\n\n\t\t\tfn.call(elem, function() {\n\t\t\t\tjQuery.dequeue(elem, type);\n\t\t\t});\n\t\t}\n\n\t\tif ( !queue.length ) {\n\t\t\tjQuery.removeData( elem, type + \"queue\", true );\n\t\t\thandleQueueMarkDefer( elem, type, \"queue\" );\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t}\n\n\t\tif ( data === undefined ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[time] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function() {\n\t\t\tvar elem = this;\n\t\t\tsetTimeout(function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t}, time );\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, object ) {\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobject = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\t\tvar defer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = elements.length,\n\t\t\tcount = 1,\n\t\t\tdeferDataKey = type + \"defer\",\n\t\t\tqueueDataKey = type + \"queue\",\n\t\t\tmarkDataKey = type + \"mark\",\n\t\t\ttmp;\n\t\tfunction resolve() {\n\t\t\tif ( !( --count ) ) {\n\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t}\n\t\t}\n\t\twhile( i-- ) {\n\t\t\tif (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||\n\t\t\t\t\t( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||\n\t\t\t\t\t\tjQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&\n\t\t\t\t\tjQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.done( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise();\n\t}\n});\n\n\n\n\nvar rclass = /[\\n\\t\\r]/g,\n\trspace = /\\s+/,\n\trreturn = /\\r/g,\n\trtype = /^(?:button|input)$/i,\n\trfocusable = /^(?:button|input|object|select|textarea)$/i,\n\trclickable = /^a(?:rea)?$/i,\n\trboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,\n\trinvalidChar = /\\:/,\n\tformHook, boolHook;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn jQuery.access( this, name, value, true, jQuery.attr );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t},\n\t\n\tprop: function( name, value ) {\n\t\treturn jQuery.access( this, name, value, true, jQuery.prop );\n\t},\n\t\n\tremoveProp: function( name ) {\n\t\tname = jQuery.propFix[ name ] || name;\n\t\treturn this.each(function() {\n\t\t\t// try/catch handles cases where IE balks (such as removing a property on window)\n\t\t\ttry {\n\t\t\t\tthis[ name ] = undefined;\n\t\t\t\tdelete this[ name ];\n\t\t\t} catch( e ) {}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.addClass( value.call(this, i, self.attr(\"class\") || \"\") );\n\t\t\t});\n\t\t}\n\n\t\tif ( value && typeof value === \"string\" ) {\n\t\t\tvar classNames = (value || \"\").split( rspace );\n\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar elem = this[i];\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !elem.className ) {\n\t\t\t\t\t\telem.className = value;\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar className = \" \" + elem.className + \" \",\n\t\t\t\t\t\t\tsetClass = elem.className;\n\n\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tif ( className.indexOf( \" \" + classNames[c] + \" \" ) < 0 ) {\n\t\t\t\t\t\t\t\tsetClass += \" \" + classNames[c];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telem.className = jQuery.trim( setClass );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.removeClass( value.call(this, i, self.attr(\"class\")) );\n\t\t\t});\n\t\t}\n\n\t\tif ( (value && typeof value === \"string\") || value === undefined ) {\n\t\t\tvar classNames = (value || \"\").split( rspace );\n\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar elem = this[i];\n\n\t\t\t\tif ( elem.nodeType === 1 && elem.className ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\tvar className = (\" \" + elem.className + \" \").replace(rclass, \" \");\n\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tclassName = className.replace(\" \" + classNames[c] + \" \", \" \");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telem.className = jQuery.trim( className );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem.className = \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisBool = typeof stateVal === \"boolean\";\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.toggleClass( value.call(this, i, self.attr(\"class\"), stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tstate = stateVal,\n\t\t\t\t\tclassNames = value.split( rspace );\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space seperated list\n\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t} else if ( type === \"undefined\" || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tjQuery._data( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// toggle whole className\n\t\t\t\tthis.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \";\n\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\tif ( (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\tval: function( value ) {\n\t\tvar hooks, ret,\n\t\t\telem = this[0];\n\t\t\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\treturn (elem.value || \"\").replace(rreturn, \"\");\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvar isFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar self = jQuery(this), val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, self.val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map(val, function ( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// attributes.value is undefined in Blackberry 4.7 but\n\t\t\t\t// uses .value. See #6932\n\t\t\t\tvar val = elem.attributes.value;\n\t\t\t\treturn !val || val.specified ? elem.value : elem.text;\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tvalues = [],\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tone = elem.type === \"select-one\";\n\n\t\t\t\t// Nothing was selected\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {\n\t\t\t\t\tvar option = options[ i ];\n\n\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\tif ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null) &&\n\t\t\t\t\t\t\t(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" )) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fixes Bug #2551 -- select.val() broken in IE after form.reset()\n\t\t\t\tif ( one && !values.length && options.length ) {\n\t\t\t\t\treturn jQuery( options[ index ] ).val();\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar values = jQuery.makeArray( value );\n\n\t\t\t\tjQuery(elem).find(\"option\").each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t},\n\n\tattrFn: {\n\t\tval: true,\n\t\tcss: true,\n\t\thtml: true,\n\t\ttext: true,\n\t\tdata: true,\n\t\twidth: true,\n\t\theight: true,\n\t\toffset: true\n\t},\n\t\n\tattrFix: {\n\t\t// Always normalize to ensure hook usage\n\t\ttabindex: \"tabIndex\"\n\t},\n\t\n\tattr: function( elem, name, value, pass ) {\n\t\tvar nType = elem.nodeType;\n\t\t\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( pass && name in jQuery.attrFn ) {\n\t\t\treturn jQuery( elem )[ name ]( value );\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( !(\"getAttribute\" in elem) ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\tvar ret, hooks,\n\t\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// Normalize the name if needed\n\t\tname = notxml && jQuery.attrFix[ name ] || name;\n\n\t\thooks = jQuery.attrHooks[ name ];\n\n\t\tif ( !hooks ) {\n\t\t\t// Use boolHook for boolean attributes\n\t\t\tif ( rboolean.test( name ) &&\n\t\t\t\t(typeof value === \"boolean\" || value === undefined || value.toLowerCase() === name.toLowerCase()) ) {\n\n\t\t\t\thooks = boolHook;\n\n\t\t\t// Use formHook for forms and if the name contains certain characters\n\t\t\t} else if ( formHook && (jQuery.nodeName( elem, \"form\" ) || rinvalidChar.test( name )) ) {\n\t\t\t\thooks = formHook;\n\t\t\t}\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn undefined;\n\n\t\t\t} else if ( hooks && \"set\" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, \"\" + value );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && notxml ) {\n\t\t\treturn hooks.get( elem, name );\n\n\t\t} else {\n\n\t\t\tret = elem.getAttribute( name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret === null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, name ) {\n\t\tvar propName;\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tname = jQuery.attrFix[ name ] || name;\n\t\t\n\t\t\tif ( jQuery.support.getSetAttribute ) {\n\t\t\t\t// Use removeAttribute in browsers that support it\n\t\t\t\telem.removeAttribute( name );\n\t\t\t} else {\n\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\telem.removeAttributeNode( elem.getAttributeNode( name ) );\n\t\t\t}\n\n\t\t\t// Set corresponding property to false for boolean attributes\n\t\t\tif ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {\n\t\t\t\telem[ propName ] = false;\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\t// We can't allow the type property to be changed (since it causes problems in IE)\n\t\t\t\tif ( rtype.test( elem.nodeName ) && elem.parentNode ) {\n\t\t\t\t\tjQuery.error( \"type property can't be changed\" );\n\t\t\t\t} else if ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to it's default in case type is set after value\n\t\t\t\t\t// This is for element creation\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tvar attributeNode = elem.getAttributeNode(\"tabIndex\");\n\n\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\tparseInt( attributeNode.value, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t0 :\n\t\t\t\t\t\tundefined;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\ttabindex: \"tabIndex\",\n\t\treadonly: \"readOnly\",\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\",\n\t\tmaxlength: \"maxLength\",\n\t\tcellspacing: \"cellSpacing\",\n\t\tcellpadding: \"cellPadding\",\n\t\trowspan: \"rowSpan\",\n\t\tcolspan: \"colSpan\",\n\t\tusemap: \"useMap\",\n\t\tframeborder: \"frameBorder\",\n\t\tcontenteditable: \"contentEditable\"\n\t},\n\t\n\tprop: function( elem, name, value ) {\n\t\tvar nType = elem.nodeType;\n\n\t\t// don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvar ret, hooks,\n\t\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// Try to normalize/fix the name\n\t\tname = notxml && jQuery.propFix[ name ] || name;\n\t\t\n\t\thooks = jQuery.propHooks[ name ];\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn (elem[ name ] = value);\n\t\t\t}\n\n\t\t} else {\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\t\t}\n\t},\n\t\n\tpropHooks: {}\n});\n\n// Hook for boolean attributes\nboolHook = {\n\tget: function( elem, name ) {\n\t\t// Align boolean attributes with corresponding properties\n\t\treturn elem[ jQuery.propFix[ name ] || name ] ?\n\t\t\tname.toLowerCase() :\n\t\t\tundefined;\n\t},\n\tset: function( elem, value, name ) {\n\t\tvar propName;\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\t// value is true since we know at this point it's type boolean and not false\n\t\t\t// Set boolean attributes to the same name and set the DOM property\n\t\t\tpropName = jQuery.propFix[ name ] || name;\n\t\t\tif ( propName in elem ) {\n\t\t\t\t// Only set the IDL specifically if it already exists on the element\n\t\t\t\telem[ propName ] = value;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, name.toLowerCase() );\n\t\t}\n\t\treturn name;\n\t}\n};\n\n// Use the value property for back compat\n// Use the formHook for button elements in IE6/7 (#1954)\njQuery.attrHooks.value = {\n\tget: function( elem, name ) {\n\t\tif ( formHook && jQuery.nodeName( elem, \"button\" ) ) {\n\t\t\treturn formHook.get( elem, name );\n\t\t}\n\t\treturn elem.value;\n\t},\n\tset: function( elem, value, name ) {\n\t\tif ( formHook && jQuery.nodeName( elem, \"button\" ) ) {\n\t\t\treturn formHook.set( elem, value, name );\n\t\t}\n\t\t// Does not return so that setAttribute is also used\n\t\telem.value = value;\n\t}\n};\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !jQuery.support.getSetAttribute ) {\n\n\t// propFix is more comprehensive and contains all fixes\n\tjQuery.attrFix = jQuery.propFix;\n\t\n\t// Use this for any attribute on a form in IE6/7\n\tformHook = jQuery.attrHooks.name = jQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret;\n\t\t\tret = elem.getAttributeNode( name );\n\t\t\t// Return undefined if nodeValue is empty string\n\t\t\treturn ret && ret.nodeValue !== \"\" ?\n\t\t\t\tret.nodeValue :\n\t\t\t\tundefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\t// Check form objects in IE (multiple bugs related)\n\t\t\t// Only use nodeValue if the attribute node exists on the form\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( ret ) {\n\t\t\t\tret.nodeValue = value;\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n\n\t// Set width and height to auto instead of 0 on empty string( Bug #8150 )\n\t// This is for removals\n\tjQuery.each([ \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\telem.setAttribute( name, \"auto\" );\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n\n// Some attributes require a special call on IE\nif ( !jQuery.support.hrefNormalized ) {\n\tjQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar ret = elem.getAttribute( name, 2 );\n\t\t\t\treturn ret === null ? undefined : ret;\n\t\t\t}\n\t\t});\n\t});\n}\n\nif ( !jQuery.support.style ) {\n\tjQuery.attrHooks.style = {\n\t\tget: function( elem ) {\n\t\t\t// Return undefined in the case of empty string\n\t\t\t// Normalize to lowercase since IE uppercases css property names\n\t\t\treturn elem.style.cssText.toLowerCase() || undefined;\n\t\t},\n\t\tset: function( elem, value ) {\n\t\t\treturn (elem.style.cssText = \"\" + value);\n\t\t}\n\t};\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n\tjQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n\tjQuery.each([ \"radio\", \"checkbox\" ], function() {\n\t\tjQuery.valHooks[ this ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t}\n\t\t};\n\t});\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);\n\t\t\t}\n\t\t}\n\t});\n});\n\n\n\n\nvar hasOwn = Object.prototype.hasOwnProperty,\n\trnamespaces = /\\.(.*)$/,\n\trformElems = /^(?:textarea|input|select)$/i,\n\trperiod = /\\./g,\n\trspaces = / /g,\n\trescape = /[^\\w\\s.|`]/g,\n\tfcleanup = function( nm ) {\n\t\treturn nm.replace(rescape, \"\\\\$&\");\n\t};\n\n/*\n * A number of helper functions used for managing events.\n * Many of the ideas behind this code originated from\n * Dean Edwards' addEvent library.\n */\njQuery.event = {\n\n\t// Bind an event to an element\n\t// Original by Dean Edwards\n\tadd: function( elem, types, handler, data ) {\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( handler === false ) {\n\t\t\thandler = returnFalse;\n\t\t} else if ( !handler ) {\n\t\t\t// Fixes bug #7229. Fix recommended by jdalton\n\t\t\treturn;\n\t\t}\n\n\t\tvar handleObjIn, handleObj;\n\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t}\n\n\t\t// Make sure that the function being executed has a unique ID\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure\n\t\tvar elemData = jQuery._data( elem );\n\n\t\t// If no elemData is found then we must be trying to bind to one of the\n\t\t// banned noData elements\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar events = elemData.events,\n\t\t\teventHandle = elemData.handle;\n\n\t\tif ( !events ) {\n\t\t\telemData.events = events = {};\n\t\t}\n\n\t\tif ( !eventHandle ) {\n\t\t\telemData.handle = eventHandle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.handle.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t}\n\n\t\t// Add elem as a property of the handle function\n\t\t// This is to prevent a memory leak with non-native events in IE.\n\t\teventHandle.elem = elem;\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = types.split(\" \");\n\n\t\tvar type, i = 0, namespaces;\n\n\t\twhile ( (type = types[ i++ ]) ) {\n\t\t\thandleObj = handleObjIn ?\n\t\t\t\tjQuery.extend({}, handleObjIn) :\n\t\t\t\t{ handler: handler, data: data };\n\n\t\t\t// Namespaced event handlers\n\t\t\tif ( type.indexOf(\".\") > -1 ) {\n\t\t\t\tnamespaces = type.split(\".\");\n\t\t\t\ttype = namespaces.shift();\n\t\t\t\thandleObj.namespace = namespaces.slice(0).sort().join(\".\");\n\n\t\t\t} else {\n\t\t\t\tnamespaces = [];\n\t\t\t\thandleObj.namespace = \"\";\n\t\t\t}\n\n\t\t\thandleObj.type = type;\n\t\t\tif ( !handleObj.guid ) {\n\t\t\t\thandleObj.guid = handler.guid;\n\t\t\t}\n\n\t\t\t// Get the current list of functions bound to this event\n\t\t\tvar handlers = events[ type ],\n\t\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// Init the event handler queue\n\t\t\tif ( !handlers ) {\n\t\t\t\thandlers = events[ type ] = [];\n\n\t\t\t\t// Check for a special event handler\n\t\t\t\t// Only use addEventListener/attachEvent if the special\n\t\t\t\t// events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add the function to the element's handler list\n\t\t\thandlers.push( handleObj );\n\n\t\t\t// Keep track of which events have been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\tglobal: {},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, pos ) {\n\t\t// don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( handler === false ) {\n\t\t\thandler = returnFalse;\n\t\t}\n\n\t\tvar ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,\n\t\t\telemData = jQuery.hasData( elem ) && jQuery._data( elem ),\n\t\t\tevents = elemData && elemData.events;\n\n\t\tif ( !elemData || !events ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// types is actually an event object here\n\t\tif ( types && types.type ) {\n\t\t\thandler = types.handler;\n\t\t\ttypes = types.type;\n\t\t}\n\n\t\t// Unbind all events for the element\n\t\tif ( !types || typeof types === \"string\" && types.charAt(0) === \".\" ) {\n\t\t\ttypes = types || \"\";\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tjQuery.event.remove( elem, type + types );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).unbind(\"mouseover mouseout\", fn);\n\t\ttypes = types.split(\" \");\n\n\t\twhile ( (type = types[ i++ ]) ) {\n\t\t\torigType = type;\n\t\t\thandleObj = null;\n\t\t\tall = type.indexOf(\".\") < 0;\n\t\t\tnamespaces = [];\n\n\t\t\tif ( !all ) {\n\t\t\t\t// Namespaced event handlers\n\t\t\t\tnamespaces = type.split(\".\");\n\t\t\t\ttype = namespaces.shift();\n\n\t\t\t\tnamespace = new RegExp(\"(^|\\\\.)\" +\n\t\t\t\t\tjQuery.map( namespaces.slice(0).sort(), fcleanup ).join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n\t\t\t}\n\n\t\t\teventType = events[ type ];\n\n\t\t\tif ( !eventType ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( !handler ) {\n\t\t\t\tfor ( j = 0; j < eventType.length; j++ ) {\n\t\t\t\t\thandleObj = eventType[ j ];\n\n\t\t\t\t\tif ( all || namespace.test( handleObj.namespace ) ) {\n\t\t\t\t\t\tjQuery.event.remove( elem, origType, handleObj.handler, j );\n\t\t\t\t\t\teventType.splice( j--, 1 );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\tfor ( j = pos || 0; j < eventType.length; j++ ) {\n\t\t\t\thandleObj = eventType[ j ];\n\n\t\t\t\tif ( handler.guid === handleObj.guid ) {\n\t\t\t\t\t// remove the given handler for the given type\n\t\t\t\t\tif ( all || namespace.test( handleObj.namespace ) ) {\n\t\t\t\t\t\tif ( pos == null ) {\n\t\t\t\t\t\t\teventType.splice( j--, 1 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( pos != null ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// remove generic event handler if no more handlers exist\n\t\t\tif ( eventType.length === 0 || pos != null && eventType.length === 1 ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tret = null;\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tvar handle = elemData.handle;\n\t\t\tif ( handle ) {\n\t\t\t\thandle.elem = null;\n\t\t\t}\n\n\t\t\tdelete elemData.events;\n\t\t\tdelete elemData.handle;\n\n\t\t\tif ( jQuery.isEmptyObject( elemData ) ) {\n\t\t\t\tjQuery.removeData( elem, undefined, true );\n\t\t\t}\n\t\t}\n\t},\n\t\n\t// Events that are safe to short-circuit if no handlers are attached.\n\t// Native DOM events should not be added, they may have inline handlers.\n\tcustomEvent: {\n\t\t\"getData\": true,\n\t\t\"setData\": true,\n\t\t\"changeData\": true\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\t\t// Event object or event type\n\t\tvar type = event.type || event,\n\t\t\tnamespaces = [],\n\t\t\texclusive;\n\n\t\tif ( type.indexOf(\"!\") >= 0 ) {\n\t\t\t// Exclusive events trigger only for the exact event (no namespaces)\n\t\t\ttype = type.slice(0, -1);\n\t\t\texclusive = true;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\n\t\tif ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {\n\t\t\t// No jQuery handlers for this event type, and it can't have inline handlers\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an Event, Object, or just an event type string\n\t\tevent = typeof event === \"object\" ?\n\t\t\t// jQuery.Event object\n\t\t\tevent[ jQuery.expando ] ? event :\n\t\t\t// Object literal\n\t\t\tnew jQuery.Event( type, event ) :\n\t\t\t// Just the event type (string)\n\t\t\tnew jQuery.Event( type );\n\n\t\tevent.type = type;\n\t\tevent.exclusive = exclusive;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = new RegExp(\"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n\t\t\n\t\t// triggerHandler() and global events don't bubble or run the default action\n\t\tif ( onlyHandlers || !elem ) {\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t}\n\n\t\t// Handle a global trigger\n\t\tif ( !elem ) {\n\t\t\t// TODO: Stop taunting the data cache; remove global events and always attach to document\n\t\t\tjQuery.each( jQuery.cache, function() {\n\t\t\t\t// internalKey variable is just used to make it easier to find\n\t\t\t\t// and potentially change this stuff later; currently it just\n\t\t\t\t// points to jQuery.expando\n\t\t\t\tvar internalKey = jQuery.expando,\n\t\t\t\t\tinternalCache = this[ internalKey ];\n\t\t\t\tif ( internalCache && internalCache.events && internalCache.events[ type ] ) {\n\t\t\t\t\tjQuery.event.trigger( event, data, internalCache.handle.elem );\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tevent.target = elem;\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data ? jQuery.makeArray( data ) : [];\n\t\tdata.unshift( event );\n\n\t\tvar cur = elem,\n\t\t\t// IE doesn't like method names with a colon (#3533, #8272)\n\t\t\tontype = type.indexOf(\":\") < 0 ? \"on\" + type : \"\";\n\n\t\t// Fire event on the current element, then bubble up the DOM tree\n\t\tdo {\n\t\t\tvar handle = jQuery._data( cur, \"handle\" );\n\n\t\t\tevent.currentTarget = cur;\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Trigger an inline bound script\n\t\t\tif ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {\n\t\t\t\tevent.result = false;\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\t// Bubble up to document, then to window\n\t\t\tcur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;\n\t\t} while ( cur && !event.isPropagationStopped() );\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !event.isDefaultPrevented() ) {\n\t\t\tvar old,\n\t\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\tif ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&\n\t\t\t\t!(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Can't use an .isFunction)() check here because IE6/7 fails that test.\n\t\t\t\t// IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.\n\t\t\t\ttry {\n\t\t\t\t\tif ( ontype && elem[ type ] ) {\n\t\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\t\told = elem[ ontype ];\n\n\t\t\t\t\t\tif ( old ) {\n\t\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\t\telem[ type ]();\n\t\t\t\t\t}\n\t\t\t\t} catch ( ieError ) {}\n\n\t\t\t\tif ( old ) {\n\t\t\t\t\telem[ ontype ] = old;\n\t\t\t\t}\n\n\t\t\t\tjQuery.event.triggered = undefined;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn event.result;\n\t},\n\n\thandle: function( event ) {\n\t\tevent = jQuery.event.fix( event || window.event );\n\t\t// Snapshot the handlers list since a called handler may add/remove events.\n\t\tvar handlers = ((jQuery._data( this, \"events\" ) || {})[ event.type ] || []).slice(0),\n\t\t\trun_all = !event.exclusive && !event.namespace,\n\t\t\targs = Array.prototype.slice.call( arguments, 0 );\n\n\t\t// Use the fix-ed Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.currentTarget = this;\n\n\t\tfor ( var j = 0, l = handlers.length; j < l; j++ ) {\n\t\t\tvar handleObj = handlers[ j ];\n\n\t\t\t// Triggered event must 1) be non-exclusive and have no namespace, or\n\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event.\n\t\t\tif ( run_all || event.namespace_re.test( handleObj.namespace ) ) {\n\t\t\t\t// Pass in a reference to the handler function itself\n\t\t\t\t// So that we can later remove it\n\t\t\t\tevent.handler = handleObj.handler;\n\t\t\t\tevent.data = handleObj.data;\n\t\t\t\tevent.handleObj = handleObj;\n\n\t\t\t\tvar ret = handleObj.handler.apply( this, args );\n\n\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\tevent.result = ret;\n\t\t\t\t\tif ( ret === false ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( event.isImmediatePropagationStopped() ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn event.result;\n\t},\n\n\tprops: \"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// store a copy of the original event object\n\t\t// and \"clone\" to set read-only properties\n\t\tvar originalEvent = event;\n\t\tevent = jQuery.Event( originalEvent );\n\n\t\tfor ( var i = this.props.length, prop; i; ) {\n\t\t\tprop = this.props[ --i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Fix target property, if necessary\n\t\tif ( !event.target ) {\n\t\t\t// Fixes #1925 where srcElement might not be defined either\n\t\t\tevent.target = event.srcElement || document;\n\t\t}\n\n\t\t// check if target is a textnode (safari)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// Add relatedTarget, if necessary\n\t\tif ( !event.relatedTarget && event.fromElement ) {\n\t\t\tevent.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;\n\t\t}\n\n\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\tif ( event.pageX == null && event.clientX != null ) {\n\t\t\tvar eventDocument = event.target.ownerDocument || document,\n\t\t\t\tdoc = eventDocument.documentElement,\n\t\t\t\tbody = eventDocument.body;\n\n\t\t\tevent.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);\n\t\t\tevent.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);\n\t\t}\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && (event.charCode != null || event.keyCode != null) ) {\n\t\t\tevent.which = event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)\n\t\tif ( !event.metaKey && event.ctrlKey ) {\n\t\t\tevent.metaKey = event.ctrlKey;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t// Note: button is not normalized, so don't use it\n\t\tif ( !event.which && event.button !== undefined ) {\n\t\t\tevent.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));\n\t\t}\n\n\t\treturn event;\n\t},\n\n\t// Deprecated, use jQuery.guid instead\n\tguid: 1E8,\n\n\t// Deprecated, use jQuery.proxy instead\n\tproxy: jQuery.proxy,\n\n\tspecial: {\n\t\tready: {\n\t\t\t// Make sure the ready event is setup\n\t\t\tsetup: jQuery.bindReady,\n\t\t\tteardown: jQuery.noop\n\t\t},\n\n\t\tlive: {\n\t\t\tadd: function( handleObj ) {\n\t\t\t\tjQuery.event.add( this,\n\t\t\t\t\tliveConvert( handleObj.origType, handleObj.selector ),\n\t\t\t\t\tjQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );\n\t\t\t},\n\n\t\t\tremove: function( handleObj ) {\n\t\t\t\tjQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tsetup: function( data, namespaces, eventHandle ) {\n\t\t\t\t// We only want to do this special case on windows\n\t\t\t\tif ( jQuery.isWindow( this ) ) {\n\t\t\t\t\tthis.onbeforeunload = eventHandle;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tteardown: function( namespaces, eventHandle ) {\n\t\t\t\tif ( this.onbeforeunload === eventHandle ) {\n\t\t\t\t\tthis.onbeforeunload = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = document.removeEventListener ?\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.removeEventListener ) {\n\t\t\telem.removeEventListener( type, handle, false );\n\t\t}\n\t} :\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.detachEvent ) {\n\t\t\telem.detachEvent( \"on\" + type, handle );\n\t\t}\n\t};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !this.preventDefault ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||\n\t\t\tsrc.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// timeStamp is buggy for some events on Firefox(#3843)\n\t// So we won't rely on the native value\n\tthis.timeStamp = jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\nfunction returnFalse() {\n\treturn false;\n}\nfunction returnTrue() {\n\treturn true;\n}\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tpreventDefault: function() {\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if preventDefault exists run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\n\t\t// otherwise set the returnValue property of the original event to false (IE)\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// if stopPropagation exists run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t\t// otherwise set the cancelBubble property of the original event to true (IE)\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t},\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse\n};\n\n// Checks if an event happened on an element within another element\n// Used in jQuery.event.special.mouseenter and mouseleave handlers\nvar withinElement = function( event ) {\n\t// Check if mouse(over|out) are still within the same parent element\n\tvar parent = event.relatedTarget;\n\n\t// set the correct event type\n\tevent.type = event.data;\n\n\t// Firefox sometimes assigns relatedTarget a XUL element\n\t// which we cannot access the parentNode property of\n\ttry {\n\n\t\t// Chrome does something similar, the parentNode property\n\t\t// can be accessed but is null.\n\t\tif ( parent && parent !== document && !parent.parentNode ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Traverse up the tree\n\t\twhile ( parent && parent !== this ) {\n\t\t\tparent = parent.parentNode;\n\t\t}\n\n\t\tif ( parent !== this ) {\n\t\t\t// handle event if we actually just moused on to a non sub-element\n\t\t\tjQuery.event.handle.apply( this, arguments );\n\t\t}\n\n\t// assuming we've left the element since we most likely mousedover a xul element\n\t} catch(e) { }\n},\n\n// In case of event delegation, we only need to rename the event.type,\n// liveHandler will take care of the rest.\ndelegate = function( event ) {\n\tevent.type = event.data;\n\tjQuery.event.handle.apply( this, arguments );\n};\n\n// Create mouseenter and mouseleave events\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tsetup: function( data ) {\n\t\t\tjQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );\n\t\t},\n\t\tteardown: function( data ) {\n\t\t\tjQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );\n\t\t}\n\t};\n});\n\n// submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function( data, namespaces ) {\n\t\t\tif ( !jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\tjQuery.event.add(this, \"click.specialSubmit\", function( e ) {\n\t\t\t\t\tvar elem = e.target,\n\t\t\t\t\t\ttype = elem.type;\n\n\t\t\t\t\tif ( (type === \"submit\" || type === \"image\") && jQuery( elem ).closest(\"form\").length ) {\n\t\t\t\t\t\ttrigger( \"submit\", this, arguments );\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tjQuery.event.add(this, \"keypress.specialSubmit\", function( e ) {\n\t\t\t\t\tvar elem = e.target,\n\t\t\t\t\t\ttype = elem.type;\n\n\t\t\t\t\tif ( (type === \"text\" || type === \"password\") && jQuery( elem ).closest(\"form\").length && e.keyCode === 13 ) {\n\t\t\t\t\t\ttrigger( \"submit\", this, arguments );\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\tteardown: function( namespaces ) {\n\t\t\tjQuery.event.remove( this, \".specialSubmit\" );\n\t\t}\n\t};\n\n}\n\n// change delegation, happens here so we have bind.\nif ( !jQuery.support.changeBubbles ) {\n\n\tvar changeFilters,\n\n\tgetVal = function( elem ) {\n\t\tvar type = elem.type, val = elem.value;\n\n\t\tif ( type === \"radio\" || type === \"checkbox\" ) {\n\t\t\tval = elem.checked;\n\n\t\t} else if ( type === \"select-multiple\" ) {\n\t\t\tval = elem.selectedIndex > -1 ?\n\t\t\t\tjQuery.map( elem.options, function( elem ) {\n\t\t\t\t\treturn elem.selected;\n\t\t\t\t}).join(\"-\") :\n\t\t\t\t\"\";\n\n\t\t} else if ( jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\tval = elem.selectedIndex;\n\t\t}\n\n\t\treturn val;\n\t},\n\n\ttestChange = function testChange( e ) {\n\t\tvar elem = e.target, data, val;\n\n\t\tif ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata = jQuery._data( elem, \"_change_data\" );\n\t\tval = getVal(elem);\n\n\t\t// the current data will be also retrieved by beforeactivate\n\t\tif ( e.type !== \"focusout\" || elem.type !== \"radio\" ) {\n\t\t\tjQuery._data( elem, \"_change_data\", val );\n\t\t}\n\n\t\tif ( data === undefined || val === data ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( data != null || val ) {\n\t\t\te.type = \"change\";\n\t\t\te.liveFired = undefined;\n\t\t\tjQuery.event.trigger( e, arguments[1], elem );\n\t\t}\n\t};\n\n\tjQuery.event.special.change = {\n\t\tfilters: {\n\t\t\tfocusout: testChange,\n\n\t\t\tbeforedeactivate: testChange,\n\n\t\t\tclick: function( e ) {\n\t\t\t\tvar elem = e.target, type = jQuery.nodeName( elem, \"input\" ) ? elem.type : \"\";\n\n\t\t\t\tif ( type === \"radio\" || type === \"checkbox\" || jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\t\ttestChange.call( this, e );\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Change has to be called before submit\n\t\t\t// Keydown will be called before keypress, which is used in submit-event delegation\n\t\t\tkeydown: function( e ) {\n\t\t\t\tvar elem = e.target, type = jQuery.nodeName( elem, \"input\" ) ? elem.type : \"\";\n\n\t\t\t\tif ( (e.keyCode === 13 && !jQuery.nodeName( elem, \"textarea\" ) ) ||\n\t\t\t\t\t(e.keyCode === 32 && (type === \"checkbox\" || type === \"radio\")) ||\n\t\t\t\t\ttype === \"select-multiple\" ) {\n\t\t\t\t\ttestChange.call( this, e );\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Beforeactivate happens also before the previous element is blurred\n\t\t\t// with this event you can't trigger a change event, but you can store\n\t\t\t// information\n\t\t\tbeforeactivate: function( e ) {\n\t\t\t\tvar elem = e.target;\n\t\t\t\tjQuery._data( elem, \"_change_data\", getVal(elem) );\n\t\t\t}\n\t\t},\n\n\t\tsetup: function( data, namespaces ) {\n\t\t\tif ( this.type === \"file\" ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor ( var type in changeFilters ) {\n\t\t\t\tjQuery.event.add( this, type + \".specialChange\", changeFilters[type] );\n\t\t\t}\n\n\t\t\treturn rformElems.test( this.nodeName );\n\t\t},\n\n\t\tteardown: function( namespaces ) {\n\t\t\tjQuery.event.remove( this, \".specialChange\" );\n\n\t\t\treturn rformElems.test( this.nodeName );\n\t\t}\n\t};\n\n\tchangeFilters = jQuery.event.special.change.filters;\n\n\t// Handle when the input is .focus()'d\n\tchangeFilters.focus = changeFilters.beforeactivate;\n}\n\nfunction trigger( type, elem, args ) {\n\t// Piggyback on a donor event to simulate a different one.\n\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t// simulated event prevents default then we do the same on the donor.\n\t// Don't pass args or remember liveFired; they apply to the donor event.\n\tvar event = jQuery.extend( {}, args[ 0 ] );\n\tevent.type = type;\n\tevent.originalEvent = {};\n\tevent.liveFired = undefined;\n\tjQuery.event.handle.call( elem, event );\n\tif ( event.isDefaultPrevented() ) {\n\t\targs[ 0 ].preventDefault();\n\t}\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler while someone wants focusin/focusout\n\t\tvar attaches = 0;\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tif ( attaches++ === 0 ) {\n\t\t\t\t\tdocument.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( --attaches === 0 ) {\n\t\t\t\t\tdocument.removeEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfunction handler( donor ) {\n\t\t\t// Donor event is always a native one; fix it and switch its type.\n\t\t\t// Let focusin/out handler cancel the donor focus/blur event.\n\t\t\tvar e = jQuery.event.fix( donor );\n\t\t\te.type = fix;\n\t\t\te.originalEvent = {};\n\t\t\tjQuery.event.trigger( e, null, e.target );\n\t\t\tif ( e.isDefaultPrevented() ) {\n\t\t\t\tdonor.preventDefault();\n\t\t\t}\n\t\t}\n\t});\n}\n\njQuery.each([\"bind\", \"one\"], function( i, name ) {\n\tjQuery.fn[ name ] = function( type, data, fn ) {\n\t\tvar handler;\n\n\t\t// Handle object literals\n\t\tif ( typeof type === \"object\" ) {\n\t\t\tfor ( var key in type ) {\n\t\t\t\tthis[ name ](key, data, type[key], fn);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( arguments.length === 2 || data === false ) {\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\tif ( name === \"one\" ) {\n\t\t\thandler = function( event ) {\n\t\t\t\tjQuery( this ).unbind( event, handler );\n\t\t\t\treturn fn.apply( this, arguments );\n\t\t\t};\n\t\t\thandler.guid = fn.guid || jQuery.guid++;\n\t\t} else {\n\t\t\thandler = fn;\n\t\t}\n\n\t\tif ( type === \"unload\" && name !== \"one\" ) {\n\t\t\tthis.one( type, data, fn );\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( this[i], type, handler, data );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t};\n});\n\njQuery.fn.extend({\n\tunbind: function( type, fn ) {\n\t\t// Handle object literals\n\t\tif ( typeof type === \"object\" && !type.preventDefault ) {\n\t\t\tfor ( var key in type ) {\n\t\t\t\tthis.unbind(key, type[key]);\n\t\t\t}\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tjQuery.event.remove( this[i], type, fn );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.live( types, data, fn, selector );\n\t},\n\n\tundelegate: function( selector, types, fn ) {\n\t\tif ( arguments.length === 0 ) {\n\t\t\treturn this.unbind( \"live\" );\n\n\t\t} else {\n\t\t\treturn this.die( types, null, fn, selector );\n\t\t}\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\n\ttriggerHandler: function( type, data ) {\n\t\tif ( this[0] ) {\n\t\t\treturn jQuery.event.trigger( type, data, this[0], true );\n\t\t}\n\t},\n\n\ttoggle: function( fn ) {\n\t\t// Save reference to arguments for access in closure\n\t\tvar args = arguments,\n\t\t\tguid = fn.guid || jQuery.guid++,\n\t\t\ti = 0,\n\t\t\ttoggler = function( event ) {\n\t\t\t\t// Figure out which function to execute\n\t\t\t\tvar lastToggle = ( jQuery.data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n\t\t\t\tjQuery.data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n\t\t\t\t// Make sure that clicks stop\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\t// and execute the function\n\t\t\t\treturn args[ lastToggle ].apply( this, arguments ) || false;\n\t\t\t};\n\n\t\t// link all the functions, so any of them can unbind this click handler\n\t\ttoggler.guid = guid;\n\t\twhile ( i < args.length ) {\n\t\t\targs[ i++ ].guid = guid;\n\t\t}\n\n\t\treturn this.click( toggler );\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n});\n\nvar liveMap = {\n\tfocus: \"focusin\",\n\tblur: \"focusout\",\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n};\n\njQuery.each([\"live\", \"die\"], function( i, name ) {\n\tjQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {\n\t\tvar type, i = 0, match, namespaces, preType,\n\t\t\tselector = origSelector || this.selector,\n\t\t\tcontext = origSelector ? this : jQuery( this.context );\n\n\t\tif ( typeof types === \"object\" && !types.preventDefault ) {\n\t\t\tfor ( var key in types ) {\n\t\t\t\tcontext[ name ]( key, data, types[key], selector );\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( name === \"die\" && !types &&\n\t\t\t\t\torigSelector && origSelector.charAt(0) === \".\" ) {\n\n\t\t\tcontext.unbind( origSelector );\n\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data === false || jQuery.isFunction( data ) ) {\n\t\t\tfn = data || returnFalse;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\ttypes = (types || \"\").split(\" \");\n\n\t\twhile ( (type = types[ i++ ]) != null ) {\n\t\t\tmatch = rnamespaces.exec( type );\n\t\t\tnamespaces = \"\";\n\n\t\t\tif ( match )  {\n\t\t\t\tnamespaces = match[0];\n\t\t\t\ttype = type.replace( rnamespaces, \"\" );\n\t\t\t}\n\n\t\t\tif ( type === \"hover\" ) {\n\t\t\t\ttypes.push( \"mouseenter\" + namespaces, \"mouseleave\" + namespaces );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpreType = type;\n\n\t\t\tif ( liveMap[ type ] ) {\n\t\t\t\ttypes.push( liveMap[ type ] + namespaces );\n\t\t\t\ttype = type + namespaces;\n\n\t\t\t} else {\n\t\t\t\ttype = (liveMap[ type ] || type) + namespaces;\n\t\t\t}\n\n\t\t\tif ( name === \"live\" ) {\n\t\t\t\t// bind live handler\n\t\t\t\tfor ( var j = 0, l = context.length; j < l; j++ ) {\n\t\t\t\t\tjQuery.event.add( context[j], \"live.\" + liveConvert( type, selector ),\n\t\t\t\t\t\t{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// unbind live handler\n\t\t\t\tcontext.unbind( \"live.\" + liveConvert( type, selector ), fn );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t};\n});\n\nfunction liveHandler( event ) {\n\tvar stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,\n\t\telems = [],\n\t\tselectors = [],\n\t\tevents = jQuery._data( this, \"events\" );\n\n\t// Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)\n\tif ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === \"click\" ) {\n\t\treturn;\n\t}\n\n\tif ( event.namespace ) {\n\t\tnamespace = new RegExp(\"(^|\\\\.)\" + event.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n\t}\n\n\tevent.liveFired = this;\n\n\tvar live = events.live.slice(0);\n\n\tfor ( j = 0; j < live.length; j++ ) {\n\t\thandleObj = live[j];\n\n\t\tif ( handleObj.origType.replace( rnamespaces, \"\" ) === event.type ) {\n\t\t\tselectors.push( handleObj.selector );\n\n\t\t} else {\n\t\t\tlive.splice( j--, 1 );\n\t\t}\n\t}\n\n\tmatch = jQuery( event.target ).closest( selectors, event.currentTarget );\n\n\tfor ( i = 0, l = match.length; i < l; i++ ) {\n\t\tclose = match[i];\n\n\t\tfor ( j = 0; j < live.length; j++ ) {\n\t\t\thandleObj = live[j];\n\n\t\t\tif ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {\n\t\t\t\telem = close.elem;\n\t\t\t\trelated = null;\n\n\t\t\t\t// Those two events require additional checking\n\t\t\t\tif ( handleObj.preType === \"mouseenter\" || handleObj.preType === \"mouseleave\" ) {\n\t\t\t\t\tevent.type = handleObj.preType;\n\t\t\t\t\trelated = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];\n\n\t\t\t\t\t// Make sure not to accidentally match a child element with the same selector\n\t\t\t\t\tif ( related && jQuery.contains( elem, related ) ) {\n\t\t\t\t\t\trelated = elem;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( !related || related !== elem ) {\n\t\t\t\t\telems.push({ elem: elem, handleObj: handleObj, level: close.level });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( i = 0, l = elems.length; i < l; i++ ) {\n\t\tmatch = elems[i];\n\n\t\tif ( maxLevel && match.level > maxLevel ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tevent.currentTarget = match.elem;\n\t\tevent.data = match.handleObj.data;\n\t\tevent.handleObj = match.handleObj;\n\n\t\tret = match.handleObj.origHandler.apply( match.elem, arguments );\n\n\t\tif ( ret === false || event.isPropagationStopped() ) {\n\t\t\tmaxLevel = match.level;\n\n\t\t\tif ( ret === false ) {\n\t\t\t\tstop = false;\n\t\t\t}\n\t\t\tif ( event.isImmediatePropagationStopped() ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn stop;\n}\n\nfunction liveConvert( type, selector ) {\n\treturn (type && type !== \"*\" ? type + \".\" : \"\") + selector.replace(rperiod, \"`\").replace(rspaces, \"&\");\n}\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\tif ( fn == null ) {\n\t\t\tfn = data;\n\t\t\tdata = null;\n\t\t}\n\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.bind( name, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n\n\tif ( jQuery.attrFn ) {\n\t\tjQuery.attrFn[ name ] = true;\n\t}\n});\n\n\n\n/*!\n * Sizzle CSS Selector Engine\n *  Copyright 2011, The Dojo Foundation\n *  Released under the MIT, BSD, and GPL Licenses.\n *  More information: http://sizzlejs.com/\n */\n(function(){\n\nvar chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n\tdone = 0,\n\ttoString = Object.prototype.toString,\n\thasDuplicate = false,\n\tbaseHasDuplicate = true,\n\trBackslash = /\\\\/g,\n\trNonWord = /\\W/;\n\n// Here we check if the JavaScript engine is using some sort of\n// optimization where it does not always call our comparision\n// function. If that is the case, discard the hasDuplicate value.\n//   Thus far that includes Google Chrome.\n[0, 0].sort(function() {\n\tbaseHasDuplicate = false;\n\treturn 0;\n});\n\nvar Sizzle = function( selector, context, results, seed ) {\n\tresults = results || [];\n\tcontext = context || document;\n\n\tvar origContext = context;\n\n\tif ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\t\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tvar m, set, checkSet, extra, ret, cur, pop, i,\n\t\tprune = true,\n\t\tcontextXML = Sizzle.isXML( context ),\n\t\tparts = [],\n\t\tsoFar = selector;\n\t\n\t// Reset the position of the chunker regexp (start from head)\n\tdo {\n\t\tchunker.exec( \"\" );\n\t\tm = chunker.exec( soFar );\n\n\t\tif ( m ) {\n\t\t\tsoFar = m[3];\n\t\t\n\t\t\tparts.push( m[1] );\n\t\t\n\t\t\tif ( m[2] ) {\n\t\t\t\textra = m[3];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while ( m );\n\n\tif ( parts.length > 1 && origPOS.exec( selector ) ) {\n\n\t\tif ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n\t\t\tset = posProcess( parts[0] + parts[1], context );\n\n\t\t} else {\n\t\t\tset = Expr.relative[ parts[0] ] ?\n\t\t\t\t[ context ] :\n\t\t\t\tSizzle( parts.shift(), context );\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tselector = parts.shift();\n\n\t\t\t\tif ( Expr.relative[ selector ] ) {\n\t\t\t\t\tselector += parts.shift();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tset = posProcess( selector, set );\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t// (but not if it'll be faster if the inner selector is an ID)\n\t\tif ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n\t\t\t\tExpr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n\n\t\t\tret = Sizzle.find( parts.shift(), context, contextXML );\n\t\t\tcontext = ret.expr ?\n\t\t\t\tSizzle.filter( ret.expr, ret.set )[0] :\n\t\t\t\tret.set[0];\n\t\t}\n\n\t\tif ( context ) {\n\t\t\tret = seed ?\n\t\t\t\t{ expr: parts.pop(), set: makeArray(seed) } :\n\t\t\t\tSizzle.find( parts.pop(), parts.length === 1 && (parts[0] === \"~\" || parts[0] === \"+\") && context.parentNode ? context.parentNode : context, contextXML );\n\n\t\t\tset = ret.expr ?\n\t\t\t\tSizzle.filter( ret.expr, ret.set ) :\n\t\t\t\tret.set;\n\n\t\t\tif ( parts.length > 0 ) {\n\t\t\t\tcheckSet = makeArray( set );\n\n\t\t\t} else {\n\t\t\t\tprune = false;\n\t\t\t}\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tcur = parts.pop();\n\t\t\t\tpop = cur;\n\n\t\t\t\tif ( !Expr.relative[ cur ] ) {\n\t\t\t\t\tcur = \"\";\n\t\t\t\t} else {\n\t\t\t\t\tpop = parts.pop();\n\t\t\t\t}\n\n\t\t\t\tif ( pop == null ) {\n\t\t\t\t\tpop = context;\n\t\t\t\t}\n\n\t\t\t\tExpr.relative[ cur ]( checkSet, pop, contextXML );\n\t\t\t}\n\n\t\t} else {\n\t\t\tcheckSet = parts = [];\n\t\t}\n\t}\n\n\tif ( !checkSet ) {\n\t\tcheckSet = set;\n\t}\n\n\tif ( !checkSet ) {\n\t\tSizzle.error( cur || selector );\n\t}\n\n\tif ( toString.call(checkSet) === \"[object Array]\" ) {\n\t\tif ( !prune ) {\n\t\t\tresults.push.apply( results, checkSet );\n\n\t\t} else if ( context && context.nodeType === 1 ) {\n\t\t\tfor ( i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\tfor ( i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\tmakeArray( checkSet, results );\n\t}\n\n\tif ( extra ) {\n\t\tSizzle( extra, origContext, results, seed );\n\t\tSizzle.uniqueSort( results );\n\t}\n\n\treturn results;\n};\n\nSizzle.uniqueSort = function( results ) {\n\tif ( sortOrder ) {\n\t\thasDuplicate = baseHasDuplicate;\n\t\tresults.sort( sortOrder );\n\n\t\tif ( hasDuplicate ) {\n\t\t\tfor ( var i = 1; i < results.length; i++ ) {\n\t\t\t\tif ( results[i] === results[ i - 1 ] ) {\n\t\t\t\t\tresults.splice( i--, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n};\n\nSizzle.matches = function( expr, set ) {\n\treturn Sizzle( expr, null, null, set );\n};\n\nSizzle.matchesSelector = function( node, expr ) {\n\treturn Sizzle( expr, null, null, [node] ).length > 0;\n};\n\nSizzle.find = function( expr, context, isXML ) {\n\tvar set;\n\n\tif ( !expr ) {\n\t\treturn [];\n\t}\n\n\tfor ( var i = 0, l = Expr.order.length; i < l; i++ ) {\n\t\tvar match,\n\t\t\ttype = Expr.order[i];\n\t\t\n\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n\t\t\tvar left = match[1];\n\t\t\tmatch.splice( 1, 1 );\n\n\t\t\tif ( left.substr( left.length - 1 ) !== \"\\\\\" ) {\n\t\t\t\tmatch[1] = (match[1] || \"\").replace( rBackslash, \"\" );\n\t\t\t\tset = Expr.find[ type ]( match, context, isXML );\n\n\t\t\t\tif ( set != null ) {\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( !set ) {\n\t\tset = typeof context.getElementsByTagName !== \"undefined\" ?\n\t\t\tcontext.getElementsByTagName( \"*\" ) :\n\t\t\t[];\n\t}\n\n\treturn { set: set, expr: expr };\n};\n\nSizzle.filter = function( expr, set, inplace, not ) {\n\tvar match, anyFound,\n\t\told = expr,\n\t\tresult = [],\n\t\tcurLoop = set,\n\t\tisXMLFilter = set && set[0] && Sizzle.isXML( set[0] );\n\n\twhile ( expr && set.length ) {\n\t\tfor ( var type in Expr.filter ) {\n\t\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n\t\t\t\tvar found, item,\n\t\t\t\t\tfilter = Expr.filter[ type ],\n\t\t\t\t\tleft = match[1];\n\n\t\t\t\tanyFound = false;\n\n\t\t\t\tmatch.splice(1,1);\n\n\t\t\t\tif ( left.substr( left.length - 1 ) === \"\\\\\" ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( curLoop === result ) {\n\t\t\t\t\tresult = [];\n\t\t\t\t}\n\n\t\t\t\tif ( Expr.preFilter[ type ] ) {\n\t\t\t\t\tmatch = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n\n\t\t\t\t\tif ( !match ) {\n\t\t\t\t\t\tanyFound = found = true;\n\n\t\t\t\t\t} else if ( match === true ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tfor ( var i = 0; (item = curLoop[i]) != null; i++ ) {\n\t\t\t\t\t\tif ( item ) {\n\t\t\t\t\t\t\tfound = filter( item, match, i, curLoop );\n\t\t\t\t\t\t\tvar pass = not ^ !!found;\n\n\t\t\t\t\t\t\tif ( inplace && found != null ) {\n\t\t\t\t\t\t\t\tif ( pass ) {\n\t\t\t\t\t\t\t\t\tanyFound = true;\n\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else if ( pass ) {\n\t\t\t\t\t\t\t\tresult.push( item );\n\t\t\t\t\t\t\t\tanyFound = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( found !== undefined ) {\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tcurLoop = result;\n\t\t\t\t\t}\n\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\n\t\t\t\t\tif ( !anyFound ) {\n\t\t\t\t\t\treturn [];\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Improper expression\n\t\tif ( expr === old ) {\n\t\t\tif ( anyFound == null ) {\n\t\t\t\tSizzle.error( expr );\n\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\told = expr;\n\t}\n\n\treturn curLoop;\n};\n\nSizzle.error = function( msg ) {\n\tthrow \"Syntax error, unrecognized expression: \" + msg;\n};\n\nvar Expr = Sizzle.selectors = {\n\torder: [ \"ID\", \"NAME\", \"TAG\" ],\n\n\tmatch: {\n\t\tID: /#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n\t\tCLASS: /\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n\t\tNAME: /\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,\n\t\tATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,\n\t\tTAG: /^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,\n\t\tCHILD: /:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,\n\t\tPOS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,\n\t\tPSEUDO: /:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n\t},\n\n\tleftMatch: {},\n\n\tattrMap: {\n\t\t\"class\": \"className\",\n\t\t\"for\": \"htmlFor\"\n\t},\n\n\tattrHandle: {\n\t\thref: function( elem ) {\n\t\t\treturn elem.getAttribute( \"href\" );\n\t\t},\n\t\ttype: function( elem ) {\n\t\t\treturn elem.getAttribute( \"type\" );\n\t\t}\n\t},\n\n\trelative: {\n\t\t\"+\": function(checkSet, part){\n\t\t\tvar isPartStr = typeof part === \"string\",\n\t\t\t\tisTag = isPartStr && !rNonWord.test( part ),\n\t\t\t\tisPartStrNotTag = isPartStr && !isTag;\n\n\t\t\tif ( isTag ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t}\n\n\t\t\tfor ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n\t\t\t\tif ( (elem = checkSet[i]) ) {\n\t\t\t\t\twhile ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n\n\t\t\t\t\tcheckSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n\t\t\t\t\t\telem || false :\n\t\t\t\t\t\telem === part;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( isPartStrNotTag ) {\n\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t}\n\t\t},\n\n\t\t\">\": function( checkSet, part ) {\n\t\t\tvar elem,\n\t\t\t\tisPartStr = typeof part === \"string\",\n\t\t\t\ti = 0,\n\t\t\t\tl = checkSet.length;\n\n\t\t\tif ( isPartStr && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\telem = checkSet[i];\n\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tvar parent = elem.parentNode;\n\t\t\t\t\t\tcheckSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\telem = checkSet[i];\n\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tcheckSet[i] = isPartStr ?\n\t\t\t\t\t\t\telem.parentNode :\n\t\t\t\t\t\t\telem.parentNode === part;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( isPartStr ) {\n\t\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t\"\": function(checkSet, part, isXML){\n\t\t\tvar nodeCheck,\n\t\t\t\tdoneName = done++,\n\t\t\t\tcheckFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t\tnodeCheck = part;\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn( \"parentNode\", part, doneName, checkSet, nodeCheck, isXML );\n\t\t},\n\n\t\t\"~\": function( checkSet, part, isXML ) {\n\t\t\tvar nodeCheck,\n\t\t\t\tdoneName = done++,\n\t\t\t\tcheckFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t\tnodeCheck = part;\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn( \"previousSibling\", part, doneName, checkSet, nodeCheck, isXML );\n\t\t}\n\t},\n\n\tfind: {\n\t\tID: function( match, context, isXML ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [m] : [];\n\t\t\t}\n\t\t},\n\n\t\tNAME: function( match, context ) {\n\t\t\tif ( typeof context.getElementsByName !== \"undefined\" ) {\n\t\t\t\tvar ret = [],\n\t\t\t\t\tresults = context.getElementsByName( match[1] );\n\n\t\t\t\tfor ( var i = 0, l = results.length; i < l; i++ ) {\n\t\t\t\t\tif ( results[i].getAttribute(\"name\") === match[1] ) {\n\t\t\t\t\t\tret.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn ret.length === 0 ? null : ret;\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( match, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( match[1] );\n\t\t\t}\n\t\t}\n\t},\n\tpreFilter: {\n\t\tCLASS: function( match, curLoop, inplace, result, not, isXML ) {\n\t\t\tmatch = \" \" + match[1].replace( rBackslash, \"\" ) + \" \";\n\n\t\t\tif ( isXML ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\tfor ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n\t\t\t\tif ( elem ) {\n\t\t\t\t\tif ( not ^ (elem.className && (\" \" + elem.className + \" \").replace(/[\\t\\n\\r]/g, \" \").indexOf(match) >= 0) ) {\n\t\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\t\tresult.push( elem );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( inplace ) {\n\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tID: function( match ) {\n\t\t\treturn match[1].replace( rBackslash, \"\" );\n\t\t},\n\n\t\tTAG: function( match, curLoop ) {\n\t\t\treturn match[1].replace( rBackslash, \"\" ).toLowerCase();\n\t\t},\n\n\t\tCHILD: function( match ) {\n\t\t\tif ( match[1] === \"nth\" ) {\n\t\t\t\tif ( !match[2] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\tmatch[2] = match[2].replace(/^\\+|\\s*/g, '');\n\n\t\t\t\t// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\n\t\t\t\tvar test = /(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(\n\t\t\t\t\tmatch[2] === \"even\" && \"2n\" || match[2] === \"odd\" && \"2n+1\" ||\n\t\t\t\t\t!/\\D/.test( match[2] ) && \"0n+\" + match[2] || match[2]);\n\n\t\t\t\t// calculate the numbers (first)n+(last) including if they are negative\n\t\t\t\tmatch[2] = (test[1] + (test[2] || 1)) - 0;\n\t\t\t\tmatch[3] = test[3] - 0;\n\t\t\t}\n\t\t\telse if ( match[2] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\t// TODO: Move to normal caching system\n\t\t\tmatch[0] = done++;\n\n\t\t\treturn match;\n\t\t},\n\n\t\tATTR: function( match, curLoop, inplace, result, not, isXML ) {\n\t\t\tvar name = match[1] = match[1].replace( rBackslash, \"\" );\n\t\t\t\n\t\t\tif ( !isXML && Expr.attrMap[name] ) {\n\t\t\t\tmatch[1] = Expr.attrMap[name];\n\t\t\t}\n\n\t\t\t// Handle if an un-quoted value was used\n\t\t\tmatch[4] = ( match[4] || match[5] || \"\" ).replace( rBackslash, \"\" );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[4] = \" \" + match[4] + \" \";\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\tPSEUDO: function( match, curLoop, inplace, result, not ) {\n\t\t\tif ( match[1] === \"not\" ) {\n\t\t\t\t// If we're dealing with a complex expression, or a simple one\n\t\t\t\tif ( ( chunker.exec(match[3]) || \"\" ).length > 1 || /^\\w/.test(match[3]) ) {\n\t\t\t\t\tmatch[3] = Sizzle(match[3], null, null, curLoop);\n\n\t\t\t\t} else {\n\t\t\t\t\tvar ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tresult.push.apply( result, ret );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn match;\n\t\t},\n\n\t\tPOS: function( match ) {\n\t\t\tmatch.unshift( true );\n\n\t\t\treturn match;\n\t\t}\n\t},\n\t\n\tfilters: {\n\t\tenabled: function( elem ) {\n\t\t\treturn elem.disabled === false && elem.type !== \"hidden\";\n\t\t},\n\n\t\tdisabled: function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\tchecked: function( elem ) {\n\t\t\treturn elem.checked === true;\n\t\t},\n\t\t\n\t\tselected: function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\t\t\t\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !!elem.firstChild;\n\t\t},\n\n\t\tempty: function( elem ) {\n\t\t\treturn !elem.firstChild;\n\t\t},\n\n\t\thas: function( elem, i, match ) {\n\t\t\treturn !!Sizzle( match[3], elem ).length;\n\t\t},\n\n\t\theader: function( elem ) {\n\t\t\treturn (/h\\d/i).test( elem.nodeName );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\tvar attr = elem.getAttribute( \"type\" ), type = elem.type;\n\t\t\t// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) \n\t\t\t// use getAttribute instead to test this case\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"text\" === type && ( attr === type || attr === null );\n\t\t},\n\n\t\tradio: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"radio\" === elem.type;\n\t\t},\n\n\t\tcheckbox: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"checkbox\" === elem.type;\n\t\t},\n\n\t\tfile: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"file\" === elem.type;\n\t\t},\n\n\t\tpassword: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"password\" === elem.type;\n\t\t},\n\n\t\tsubmit: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn (name === \"input\" || name === \"button\") && \"submit\" === elem.type;\n\t\t},\n\n\t\timage: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"image\" === elem.type;\n\t\t},\n\n\t\treset: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn (name === \"input\" || name === \"button\") && \"reset\" === elem.type;\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && \"button\" === elem.type || name === \"button\";\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn (/input|select|textarea|button/i).test( elem.nodeName );\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === elem.ownerDocument.activeElement;\n\t\t}\n\t},\n\tsetFilters: {\n\t\tfirst: function( elem, i ) {\n\t\t\treturn i === 0;\n\t\t},\n\n\t\tlast: function( elem, i, match, array ) {\n\t\t\treturn i === array.length - 1;\n\t\t},\n\n\t\teven: function( elem, i ) {\n\t\t\treturn i % 2 === 0;\n\t\t},\n\n\t\todd: function( elem, i ) {\n\t\t\treturn i % 2 === 1;\n\t\t},\n\n\t\tlt: function( elem, i, match ) {\n\t\t\treturn i < match[3] - 0;\n\t\t},\n\n\t\tgt: function( elem, i, match ) {\n\t\t\treturn i > match[3] - 0;\n\t\t},\n\n\t\tnth: function( elem, i, match ) {\n\t\t\treturn match[3] - 0 === i;\n\t\t},\n\n\t\teq: function( elem, i, match ) {\n\t\t\treturn match[3] - 0 === i;\n\t\t}\n\t},\n\tfilter: {\n\t\tPSEUDO: function( elem, match, i, array ) {\n\t\t\tvar name = match[1],\n\t\t\t\tfilter = Expr.filters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\n\t\t\t} else if ( name === \"contains\" ) {\n\t\t\t\treturn (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || \"\").indexOf(match[3]) >= 0;\n\n\t\t\t} else if ( name === \"not\" ) {\n\t\t\t\tvar not = match[3];\n\n\t\t\t\tfor ( var j = 0, l = not.length; j < l; j++ ) {\n\t\t\t\t\tif ( not[j] === elem ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t} else {\n\t\t\t\tSizzle.error( name );\n\t\t\t}\n\t\t},\n\n\t\tCHILD: function( elem, match ) {\n\t\t\tvar type = match[1],\n\t\t\t\tnode = elem;\n\n\t\t\tswitch ( type ) {\n\t\t\t\tcase \"only\":\n\t\t\t\tcase \"first\":\n\t\t\t\t\twhile ( (node = node.previousSibling) )\t {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n\t\t\t\t\t\t\treturn false; \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( type === \"first\" ) { \n\t\t\t\t\t\treturn true; \n\t\t\t\t\t}\n\n\t\t\t\t\tnode = elem;\n\n\t\t\t\tcase \"last\":\n\t\t\t\t\twhile ( (node = node.nextSibling) )\t {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n\t\t\t\t\t\t\treturn false; \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\tcase \"nth\":\n\t\t\t\t\tvar first = match[2],\n\t\t\t\t\t\tlast = match[3];\n\n\t\t\t\t\tif ( first === 1 && last === 0 ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar doneName = match[0],\n\t\t\t\t\t\tparent = elem.parentNode;\n\t\n\t\t\t\t\tif ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\n\t\t\t\t\t\tvar count = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor ( node = parent.firstChild; node; node = node.nextSibling ) {\n\t\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\tnode.nodeIndex = ++count;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} \n\n\t\t\t\t\t\tparent.sizcache = doneName;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar diff = elem.nodeIndex - last;\n\n\t\t\t\t\tif ( first === 0 ) {\n\t\t\t\t\t\treturn diff === 0;\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tID: function( elem, match ) {\n\t\t\treturn elem.nodeType === 1 && elem.getAttribute(\"id\") === match;\n\t\t},\n\n\t\tTAG: function( elem, match ) {\n\t\t\treturn (match === \"*\" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;\n\t\t},\n\t\t\n\t\tCLASS: function( elem, match ) {\n\t\t\treturn (\" \" + (elem.className || elem.getAttribute(\"class\")) + \" \")\n\t\t\t\t.indexOf( match ) > -1;\n\t\t},\n\n\t\tATTR: function( elem, match ) {\n\t\t\tvar name = match[1],\n\t\t\t\tresult = Expr.attrHandle[ name ] ?\n\t\t\t\t\tExpr.attrHandle[ name ]( elem ) :\n\t\t\t\t\telem[ name ] != null ?\n\t\t\t\t\t\telem[ name ] :\n\t\t\t\t\t\telem.getAttribute( name ),\n\t\t\t\tvalue = result + \"\",\n\t\t\t\ttype = match[2],\n\t\t\t\tcheck = match[4];\n\n\t\t\treturn result == null ?\n\t\t\t\ttype === \"!=\" :\n\t\t\t\ttype === \"=\" ?\n\t\t\t\tvalue === check :\n\t\t\t\ttype === \"*=\" ?\n\t\t\t\tvalue.indexOf(check) >= 0 :\n\t\t\t\ttype === \"~=\" ?\n\t\t\t\t(\" \" + value + \" \").indexOf(check) >= 0 :\n\t\t\t\t!check ?\n\t\t\t\tvalue && result !== false :\n\t\t\t\ttype === \"!=\" ?\n\t\t\t\tvalue !== check :\n\t\t\t\ttype === \"^=\" ?\n\t\t\t\tvalue.indexOf(check) === 0 :\n\t\t\t\ttype === \"$=\" ?\n\t\t\t\tvalue.substr(value.length - check.length) === check :\n\t\t\t\ttype === \"|=\" ?\n\t\t\t\tvalue === check || value.substr(0, check.length + 1) === check + \"-\" :\n\t\t\t\tfalse;\n\t\t},\n\n\t\tPOS: function( elem, match, i, array ) {\n\t\t\tvar name = match[2],\n\t\t\t\tfilter = Expr.setFilters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\t\t\t}\n\t\t}\n\t}\n};\n\nvar origPOS = Expr.match.POS,\n\tfescape = function(all, num){\n\t\treturn \"\\\\\" + (num - 0 + 1);\n\t};\n\nfor ( var type in Expr.match ) {\n\tExpr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\\[]*\\])(?![^\\(]*\\))/.source) );\n\tExpr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, fescape) );\n}\n\nvar makeArray = function( array, results ) {\n\tarray = Array.prototype.slice.call( array, 0 );\n\n\tif ( results ) {\n\t\tresults.push.apply( results, array );\n\t\treturn results;\n\t}\n\t\n\treturn array;\n};\n\n// Perform a simple check to determine if the browser is capable of\n// converting a NodeList to an array using builtin methods.\n// Also verifies that the returned array holds DOM nodes\n// (which is not the case in the Blackberry browser)\ntry {\n\tArray.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;\n\n// Provide a fallback method if it does not work\n} catch( e ) {\n\tmakeArray = function( array, results ) {\n\t\tvar i = 0,\n\t\t\tret = results || [];\n\n\t\tif ( toString.call(array) === \"[object Array]\" ) {\n\t\t\tArray.prototype.push.apply( ret, array );\n\n\t\t} else {\n\t\t\tif ( typeof array.length === \"number\" ) {\n\t\t\t\tfor ( var l = array.length; i < l; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( ; array[i]; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nvar sortOrder, siblingCheck;\n\nif ( document.documentElement.compareDocumentPosition ) {\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n\t\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t\t}\n\n\t\treturn a.compareDocumentPosition(b) & 4 ? -1 : 1;\n\t};\n\n} else {\n\tsortOrder = function( a, b ) {\n\t\t// The nodes are identical, we can exit early\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\n\t\t// Fallback to using sourceIndex (in IE) if it's available on both nodes\n\t\t} else if ( a.sourceIndex && b.sourceIndex ) {\n\t\t\treturn a.sourceIndex - b.sourceIndex;\n\t\t}\n\n\t\tvar al, bl,\n\t\t\tap = [],\n\t\t\tbp = [],\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tcur = aup;\n\n\t\t// If the nodes are siblings (or identical) we can do a quick check\n\t\tif ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\n\t\t// If no parents were found then the nodes are disconnected\n\t\t} else if ( !aup ) {\n\t\t\treturn -1;\n\n\t\t} else if ( !bup ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Otherwise they're somewhere else in the tree so we need\n\t\t// to build up a full list of the parentNodes for comparison\n\t\twhile ( cur ) {\n\t\t\tap.unshift( cur );\n\t\t\tcur = cur.parentNode;\n\t\t}\n\n\t\tcur = bup;\n\n\t\twhile ( cur ) {\n\t\t\tbp.unshift( cur );\n\t\t\tcur = cur.parentNode;\n\t\t}\n\n\t\tal = ap.length;\n\t\tbl = bp.length;\n\n\t\t// Start walking down the tree looking for a discrepancy\n\t\tfor ( var i = 0; i < al && i < bl; i++ ) {\n\t\t\tif ( ap[i] !== bp[i] ) {\n\t\t\t\treturn siblingCheck( ap[i], bp[i] );\n\t\t\t}\n\t\t}\n\n\t\t// We ended someplace up the tree so do a sibling check\n\t\treturn i === al ?\n\t\t\tsiblingCheck( a, bp[i], -1 ) :\n\t\t\tsiblingCheck( ap[i], b, 1 );\n\t};\n\n\tsiblingCheck = function( a, b, ret ) {\n\t\tif ( a === b ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tvar cur = a.nextSibling;\n\n\t\twhile ( cur ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tcur = cur.nextSibling;\n\t\t}\n\n\t\treturn 1;\n\t};\n}\n\n// Utility function for retreiving the text value of an array of DOM nodes\nSizzle.getText = function( elems ) {\n\tvar ret = \"\", elem;\n\n\tfor ( var i = 0; elems[i]; i++ ) {\n\t\telem = elems[i];\n\n\t\t// Get the text from text nodes and CDATA nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 4 ) {\n\t\t\tret += elem.nodeValue;\n\n\t\t// Traverse everything else, except comment nodes\n\t\t} else if ( elem.nodeType !== 8 ) {\n\t\t\tret += Sizzle.getText( elem.childNodes );\n\t\t}\n\t}\n\n\treturn ret;\n};\n\n// Check to see if the browser returns elements by name when\n// querying by getElementById (and provide a workaround)\n(function(){\n\t// We're going to inject a fake input element with a specified name\n\tvar form = document.createElement(\"div\"),\n\t\tid = \"script\" + (new Date()).getTime(),\n\t\troot = document.documentElement;\n\n\tform.innerHTML = \"<a name='\" + id + \"'/>\";\n\n\t// Inject it into the root element, check its status, and remove it quickly\n\troot.insertBefore( form, root.firstChild );\n\n\t// The workaround has to do additional checks after a getElementById\n\t// Which slows things down for other browsers (hence the branching)\n\tif ( document.getElementById( id ) ) {\n\t\tExpr.find.ID = function( match, context, isXML ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\n\t\t\t\treturn m ?\n\t\t\t\t\tm.id === match[1] || typeof m.getAttributeNode !== \"undefined\" && m.getAttributeNode(\"id\").nodeValue === match[1] ?\n\t\t\t\t\t\t[m] :\n\t\t\t\t\t\tundefined :\n\t\t\t\t\t[];\n\t\t\t}\n\t\t};\n\n\t\tExpr.filter.ID = function( elem, match ) {\n\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\n\t\t\treturn elem.nodeType === 1 && node && node.nodeValue === match;\n\t\t};\n\t}\n\n\troot.removeChild( form );\n\n\t// release memory in IE\n\troot = form = null;\n})();\n\n(function(){\n\t// Check to see if the browser returns only elements\n\t// when doing getElementsByTagName(\"*\")\n\n\t// Create a fake element\n\tvar div = document.createElement(\"div\");\n\tdiv.appendChild( document.createComment(\"\") );\n\n\t// Make sure no comments are found\n\tif ( div.getElementsByTagName(\"*\").length > 0 ) {\n\t\tExpr.find.TAG = function( match, context ) {\n\t\t\tvar results = context.getElementsByTagName( match[1] );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( match[1] === \"*\" ) {\n\t\t\t\tvar tmp = [];\n\n\t\t\t\tfor ( var i = 0; results[i]; i++ ) {\n\t\t\t\t\tif ( results[i].nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresults = tmp;\n\t\t\t}\n\n\t\t\treturn results;\n\t\t};\n\t}\n\n\t// Check to see if an attribute returns normalized href attributes\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\n\tif ( div.firstChild && typeof div.firstChild.getAttribute !== \"undefined\" &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") !== \"#\" ) {\n\n\t\tExpr.attrHandle.href = function( elem ) {\n\t\t\treturn elem.getAttribute( \"href\", 2 );\n\t\t};\n\t}\n\n\t// release memory in IE\n\tdiv = null;\n})();\n\nif ( document.querySelectorAll ) {\n\t(function(){\n\t\tvar oldSizzle = Sizzle,\n\t\t\tdiv = document.createElement(\"div\"),\n\t\t\tid = \"__sizzle__\";\n\n\t\tdiv.innerHTML = \"<p class='TEST'></p>\";\n\n\t\t// Safari can't handle uppercase or unicode characters when\n\t\t// in quirks mode.\n\t\tif ( div.querySelectorAll && div.querySelectorAll(\".TEST\").length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tSizzle = function( query, context, extra, seed ) {\n\t\t\tcontext = context || document;\n\n\t\t\t// Only use querySelectorAll on non-XML documents\n\t\t\t// (ID selectors don't work in non-HTML documents)\n\t\t\tif ( !seed && !Sizzle.isXML(context) ) {\n\t\t\t\t// See if we find a selector to speed up\n\t\t\t\tvar match = /^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec( query );\n\t\t\t\t\n\t\t\t\tif ( match && (context.nodeType === 1 || context.nodeType === 9) ) {\n\t\t\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t\t\tif ( match[1] ) {\n\t\t\t\t\t\treturn makeArray( context.getElementsByTagName( query ), extra );\n\t\t\t\t\t\n\t\t\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t\t\t} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {\n\t\t\t\t\t\treturn makeArray( context.getElementsByClassName( match[2] ), extra );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( context.nodeType === 9 ) {\n\t\t\t\t\t// Speed-up: Sizzle(\"body\")\n\t\t\t\t\t// The body element only exists once, optimize finding it\n\t\t\t\t\tif ( query === \"body\" && context.body ) {\n\t\t\t\t\t\treturn makeArray( [ context.body ], extra );\n\t\t\t\t\t\t\n\t\t\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\t\t\t} else if ( match && match[3] ) {\n\t\t\t\t\t\tvar elem = context.getElementById( match[3] );\n\n\t\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === match[3] ) {\n\t\t\t\t\t\t\t\treturn makeArray( [ elem ], extra );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn makeArray( [], extra );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn makeArray( context.querySelectorAll(query), extra );\n\t\t\t\t\t} catch(qsaError) {}\n\n\t\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t\t// IE 8 doesn't work on object elements\n\t\t\t\t} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\t\tvar oldContext = context,\n\t\t\t\t\t\told = context.getAttribute( \"id\" ),\n\t\t\t\t\t\tnid = old || id,\n\t\t\t\t\t\thasParent = context.parentNode,\n\t\t\t\t\t\trelativeHierarchySelector = /^\\s*[+~]/.test( query );\n\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnid = nid.replace( /'/g, \"\\\\$&\" );\n\t\t\t\t\t}\n\t\t\t\t\tif ( relativeHierarchySelector && hasParent ) {\n\t\t\t\t\t\tcontext = context.parentNode;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif ( !relativeHierarchySelector || hasParent ) {\n\t\t\t\t\t\t\treturn makeArray( context.querySelectorAll( \"[id='\" + nid + \"'] \" + query ), extra );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} catch(pseudoError) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\t\toldContext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\treturn oldSizzle(query, context, extra, seed);\n\t\t};\n\n\t\tfor ( var prop in oldSizzle ) {\n\t\t\tSizzle[ prop ] = oldSizzle[ prop ];\n\t\t}\n\n\t\t// release memory in IE\n\t\tdiv = null;\n\t})();\n}\n\n(function(){\n\tvar html = document.documentElement,\n\t\tmatches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;\n\n\tif ( matches ) {\n\t\t// Check to see if it's possible to do matchesSelector\n\t\t// on a disconnected node (IE 9 fails this)\n\t\tvar disconnectedMatch = !matches.call( document.createElement( \"div\" ), \"div\" ),\n\t\t\tpseudoWorks = false;\n\n\t\ttry {\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( document.documentElement, \"[test!='']:sizzle\" );\n\t\n\t\t} catch( pseudoError ) {\n\t\t\tpseudoWorks = true;\n\t\t}\n\n\t\tSizzle.matchesSelector = function( node, expr ) {\n\t\t\t// Make sure that attribute selectors are quoted\n\t\t\texpr = expr.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g, \"='$1']\");\n\n\t\t\tif ( !Sizzle.isXML( node ) ) {\n\t\t\t\ttry { \n\t\t\t\t\tif ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {\n\t\t\t\t\t\tvar ret = matches.call( node, expr );\n\n\t\t\t\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\t\t\t\tif ( ret || !disconnectedMatch ||\n\t\t\t\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t\t\t\t// fragment in IE 9, so check for that\n\t\t\t\t\t\t\t\tnode.document && node.document.nodeType !== 11 ) {\n\t\t\t\t\t\t\treturn ret;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\treturn Sizzle(expr, null, null, [node]).length > 0;\n\t\t};\n\t}\n})();\n\n(function(){\n\tvar div = document.createElement(\"div\");\n\n\tdiv.innerHTML = \"<div class='test e'></div><div class='test'></div>\";\n\n\t// Opera can't find a second classname (in 9.6)\n\t// Also, make sure that getElementsByClassName actually exists\n\tif ( !div.getElementsByClassName || div.getElementsByClassName(\"e\").length === 0 ) {\n\t\treturn;\n\t}\n\n\t// Safari caches class attributes, doesn't catch changes (in 3.2)\n\tdiv.lastChild.className = \"e\";\n\n\tif ( div.getElementsByClassName(\"e\").length === 1 ) {\n\t\treturn;\n\t}\n\t\n\tExpr.order.splice(1, 0, \"CLASS\");\n\tExpr.find.CLASS = function( match, context, isXML ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && !isXML ) {\n\t\t\treturn context.getElementsByClassName(match[1]);\n\t\t}\n\t};\n\n\t// release memory in IE\n\tdiv = null;\n})();\n\nfunction dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\n\t\tif ( elem ) {\n\t\t\tvar match = false;\n\n\t\t\telem = elem[dir];\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem.sizcache === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 && !isXML ){\n\t\t\t\t\telem.sizcache = doneName;\n\t\t\t\t\telem.sizset = i;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeName.toLowerCase() === cur ) {\n\t\t\t\t\tmatch = elem;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nfunction dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\n\t\tif ( elem ) {\n\t\t\tvar match = false;\n\t\t\t\n\t\t\telem = elem[dir];\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem.sizcache === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !isXML ) {\n\t\t\t\t\t\telem.sizcache = doneName;\n\t\t\t\t\t\telem.sizset = i;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( typeof cur !== \"string\" ) {\n\t\t\t\t\t\tif ( elem === cur ) {\n\t\t\t\t\t\t\tmatch = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n\t\t\t\t\t\tmatch = elem;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nif ( document.documentElement.contains ) {\n\tSizzle.contains = function( a, b ) {\n\t\treturn a !== b && (a.contains ? a.contains(b) : true);\n\t};\n\n} else if ( document.documentElement.compareDocumentPosition ) {\n\tSizzle.contains = function( a, b ) {\n\t\treturn !!(a.compareDocumentPosition(b) & 16);\n\t};\n\n} else {\n\tSizzle.contains = function() {\n\t\treturn false;\n\t};\n}\n\nSizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833) \n\tvar documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\nvar posProcess = function( selector, context ) {\n\tvar match,\n\t\ttmpSet = [],\n\t\tlater = \"\",\n\t\troot = context.nodeType ? [context] : context;\n\n\t// Position selectors must be done after the filter\n\t// And so must :not(positional) so we move all PSEUDOs to the end\n\twhile ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n\t\tlater += match[0];\n\t\tselector = selector.replace( Expr.match.PSEUDO, \"\" );\n\t}\n\n\tselector = Expr.relative[selector] ? selector + \"*\" : selector;\n\n\tfor ( var i = 0, l = root.length; i < l; i++ ) {\n\t\tSizzle( selector, root[i], tmpSet );\n\t}\n\n\treturn Sizzle.filter( later, tmpSet );\n};\n\n// EXPOSE\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.filters;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n})();\n\n\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prevUntil|prevAll)/,\n\t// Note: This RegExp should be improved, or likely pulled from Sizzle\n\trmultiselector = /,/,\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\tslice = Array.prototype.slice,\n\tPOS = jQuery.expr.match.POS,\n\t// methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar self = this,\n\t\t\ti, l;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0, l = self.length; i < l; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tvar ret = this.pushStack( \"\", \"find\", selector ),\n\t\t\tlength, n, r;\n\n\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\tlength = ret.length;\n\t\t\tjQuery.find( selector, this[i], ret );\n\n\t\t\tif ( i > 0 ) {\n\t\t\t\t// Make sure that the results are unique\n\t\t\t\tfor ( n = length; n < ret.length; n++ ) {\n\t\t\t\t\tfor ( r = 0; r < length; r++ ) {\n\t\t\t\t\t\tif ( ret[r] === ret[n] ) {\n\t\t\t\t\t\t\tret.splice(n--, 1);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar targets = jQuery( target );\n\t\treturn this.filter(function() {\n\t\t\tfor ( var i = 0, l = targets.length; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false), \"not\", selector);\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true), \"filter\", selector );\n\t},\n\n\tis: function( selector ) {\n\t\treturn !!selector && ( typeof selector === \"string\" ?\n\t\t\tjQuery.filter( selector, this ).length > 0 :\n\t\t\tthis.filter( selector ).length > 0 );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar ret = [], i, l, cur = this[0];\n\t\t\n\t\t// Array\n\t\tif ( jQuery.isArray( selectors ) ) {\n\t\t\tvar match, selector,\n\t\t\t\tmatches = {},\n\t\t\t\tlevel = 1;\n\n\t\t\tif ( cur && selectors.length ) {\n\t\t\t\tfor ( i = 0, l = selectors.length; i < l; i++ ) {\n\t\t\t\t\tselector = selectors[i];\n\n\t\t\t\t\tif ( !matches[ selector ] ) {\n\t\t\t\t\t\tmatches[ selector ] = POS.test( selector ) ?\n\t\t\t\t\t\t\tjQuery( selector, context || this.context ) :\n\t\t\t\t\t\t\tselector;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n\t\t\t\t\tfor ( selector in matches ) {\n\t\t\t\t\t\tmatch = matches[ selector ];\n\n\t\t\t\t\t\tif ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {\n\t\t\t\t\t\t\tret.push({ selector: selector, elem: cur, level: level });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcur = cur.parentNode;\n\t\t\t\t\tlevel++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\t// String\n\t\tvar pos = POS.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\tcur = this[i];\n\n\t\t\twhile ( cur ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n\t\t\t\t\tret.push( cur );\n\t\t\t\t\tbreak;\n\n\t\t\t\t} else {\n\t\t\t\t\tcur = cur.parentNode;\n\t\t\t\t\tif ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tret = ret.length > 1 ? jQuery.unique( ret ) : ret;\n\n\t\treturn this.pushStack( ret, \"closest\", selectors );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\t\tif ( !elem || typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0],\n\t\t\t\t// If it receives a string, the selector is used\n\t\t\t\t// If it receives nothing, the siblings are used\n\t\t\t\telem ? jQuery( elem ) : this.parent().children() );\n\t\t}\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context ) :\n\t\t\t\tjQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n\t\t\tall :\n\t\t\tjQuery.unique( all ) );\n\t},\n\n\tandSelf: function() {\n\t\treturn this.add( this.prevObject );\n\t}\n});\n\n// A painfully simple check to see if an element is disconnected\n// from a document (should be improved, where feasible).\nfunction isDisconnected( node ) {\n\treturn !node || !node.parentNode || node.parentNode.nodeType === 11;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( elem.parentNode.firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.makeArray( elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until ),\n\t\t\t// The variable 'args' was introduced in\n\t\t\t// https://github.com/jquery/jquery/commit/52a0238\n\t\t\t// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.\n\t\t\t// http://code.google.com/p/v8/issues/detail?id=1050\n\t\t\targs = slice.call(arguments);\n\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n\t\tif ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret, name, args.join(\",\") );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn elems.length === 1 ?\n\t\t\tjQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n\t\t\tjQuery.find.matches(expr, elems);\n\t},\n\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\tcur = elem[ dir ];\n\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tnth: function( cur, result, dir, elem ) {\n\t\tresult = result || 1;\n\t\tvar num = 0;\n\n\t\tfor ( ; cur; cur = cur[dir] ) {\n\t\t\tif ( cur.nodeType === 1 && ++num === result ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn cur;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n\t// Can't pass null or undefined to indexOf in Firefox 4\n\t// Set to 0 to skip string check\n\tqualifier = qualifier || 0;\n\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\tvar retVal = !!qualifier.call( elem, i, elem );\n\t\t\treturn retVal === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\treturn (elem === qualifier) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem, i ) {\n\t\treturn (jQuery.inArray( elem, qualifier ) >= 0) === keep;\n\t});\n}\n\n\n\n\nvar rinlinejQuery = / jQuery\\d+=\"(?:\\d+|null)\"/g,\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnocache = /<(?:script|object|embed|option|style)/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /\\/(java|ecma)script/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\t_default: [ 0, \"\", \"\" ]\n\t};\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\nif ( !jQuery.support.htmlSerialize ) {\n\twrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n}\n\njQuery.fn.extend({\n\ttext: function( text ) {\n\t\tif ( jQuery.isFunction(text) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery( this );\n\n\t\t\t\tself.text( text.call(this, i, self.text()) );\n\t\t\t});\n\t\t}\n\n\t\tif ( typeof text !== \"object\" && text !== undefined ) {\n\t\t\treturn this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );\n\t\t}\n\n\t\treturn jQuery.text( this );\n\t},\n\n\twrapAll: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n\t\t\tif ( this[0].parentNode ) {\n\t\t\t\twrap.insertBefore( this[0] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery( this ).wrapAll( html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = jQuery(arguments[0]);\n\t\t\tset.push.apply( set, this.toArray() );\n\t\t\treturn this.pushStack( set, \"before\", arguments );\n\t\t}\n\t},\n\n\tafter: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = this.pushStack( this, \"after\", arguments );\n\t\t\tset.push.apply( set, jQuery(arguments[0]).toArray() );\n\t\t\treturn set;\n\t\t}\n\t},\n\n\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length ) {\n\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\t\tjQuery.cleanData( elem.getElementsByTagName(\"*\") );\n\t\t\t\t\tjQuery.cleanData( [ elem ] );\n\t\t\t\t}\n\n\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( elem.getElementsByTagName(\"*\") );\n\t\t\t}\n\n\t\t\t// Remove any remaining nodes\n\t\t\twhile ( elem.firstChild ) {\n\t\t\t\telem.removeChild( elem.firstChild );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function () {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\tif ( value === undefined ) {\n\t\t\treturn this[0] && this[0].nodeType === 1 ?\n\t\t\t\tthis[0].innerHTML.replace(rinlinejQuery, \"\") :\n\t\t\t\tnull;\n\n\t\t// See if we can take a shortcut and just use innerHTML\n\t\t} else if ( typeof value === \"string\" && !rnocache.test( value ) &&\n\t\t\t(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&\n\t\t\t!wrapMap[ (rtagName.exec( value ) || [\"\", \"\"])[1].toLowerCase() ] ) {\n\n\t\t\tvalue = value.replace(rxhtmlTag, \"<$1></$2>\");\n\n\t\t\ttry {\n\t\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\tif ( this[i].nodeType === 1 ) {\n\t\t\t\t\t\tjQuery.cleanData( this[i].getElementsByTagName(\"*\") );\n\t\t\t\t\t\tthis[i].innerHTML = value;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t} catch(e) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\n\t\t} else if ( jQuery.isFunction( value ) ) {\n\t\t\tthis.each(function(i){\n\t\t\t\tvar self = jQuery( this );\n\n\t\t\t\tself.html( value.call(this, i, self.html()) );\n\t\t\t});\n\n\t\t} else {\n\t\t\tthis.empty().append( value );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\treplaceWith: function( value ) {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t\t// this can help fix replacing a parent with child elements\n\t\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\t\treturn this.each(function(i) {\n\t\t\t\t\tvar self = jQuery(this), old = self.html();\n\t\t\t\t\tself.replaceWith( value.call( this, i, old ) );\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif ( typeof value !== \"string\" ) {\n\t\t\t\tvalue = jQuery( value ).detach();\n\t\t\t}\n\n\t\t\treturn this.each(function() {\n\t\t\t\tvar next = this.nextSibling,\n\t\t\t\t\tparent = this.parentNode;\n\n\t\t\t\tjQuery( this ).remove();\n\n\t\t\t\tif ( next ) {\n\t\t\t\t\tjQuery(next).before( value );\n\t\t\t\t} else {\n\t\t\t\t\tjQuery(parent).append( value );\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\treturn this.length ?\n\t\t\t\tthis.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), \"replaceWith\", value ) :\n\t\t\t\tthis;\n\t\t}\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\t\tvar results, first, fragment, parent,\n\t\t\tvalue = args[0],\n\t\t\tscripts = [];\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === \"string\" && rchecked.test( value ) ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery(this).domManip( args, table, callback, true );\n\t\t\t});\n\t\t}\n\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\targs[0] = value.call(this, i, table ? self.html() : undefined);\n\t\t\t\tself.domManip( args, table, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\tparent = value && value.parentNode;\n\n\t\t\t// If we're in a fragment, just use that instead of building a new one\n\t\t\tif ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {\n\t\t\t\tresults = { fragment: parent };\n\n\t\t\t} else {\n\t\t\t\tresults = jQuery.buildFragment( args, this, scripts );\n\t\t\t}\n\n\t\t\tfragment = results.fragment;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfirst = fragment = fragment.firstChild;\n\t\t\t} else {\n\t\t\t\tfirst = fragment.firstChild;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\ttable = table && jQuery.nodeName( first, \"tr\" );\n\n\t\t\t\tfor ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {\n\t\t\t\t\tcallback.call(\n\t\t\t\t\t\ttable ?\n\t\t\t\t\t\t\troot(this[i], first) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\t// Make sure that we do not leak memory by inadvertently discarding\n\t\t\t\t\t\t// the original fragment (which might have attached data) instead of\n\t\t\t\t\t\t// using it; in addition, use the original fragment object for the last\n\t\t\t\t\t\t// item instead of first because it can end up being emptied incorrectly\n\t\t\t\t\t\t// in certain situations (Bug #8070).\n\t\t\t\t\t\t// Fragments from the fragment cache must always be cloned and never used\n\t\t\t\t\t\t// in place.\n\t\t\t\t\t\tresults.cacheable || (l > 1 && i < lastIndex) ?\n\t\t\t\t\t\t\tjQuery.clone( fragment, true, true ) :\n\t\t\t\t\t\t\tfragment\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( scripts.length ) {\n\t\t\t\tjQuery.each( scripts, evalScript );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\nfunction root( elem, cur ) {\n\treturn jQuery.nodeName(elem, \"table\") ?\n\t\t(elem.getElementsByTagName(\"tbody\")[0] ||\n\t\telem.appendChild(elem.ownerDocument.createElement(\"tbody\"))) :\n\t\telem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar internalKey = jQuery.expando,\n\t\toldData = jQuery.data( src ),\n\t\tcurData = jQuery.data( dest, oldData );\n\n\t// Switch to use the internal data object, if it exists, for the next\n\t// stage of data copying\n\tif ( (oldData = oldData[ internalKey ]) ) {\n\t\tvar events = oldData.events;\n\t\t\t\tcurData = curData[ internalKey ] = jQuery.extend({}, oldData);\n\n\t\tif ( events ) {\n\t\t\tdelete curData.handle;\n\t\t\tcurData.events = {};\n\n\t\t\tfor ( var type in events ) {\n\t\t\t\tfor ( var i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? \".\" : \"\" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cloneFixAttributes( src, dest ) {\n\tvar nodeName;\n\n\t// We do not need to do anything for non-Elements\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// clearAttributes removes the attributes, which we don't want,\n\t// but also removes the attachEvent events, which we *do* want\n\tif ( dest.clearAttributes ) {\n\t\tdest.clearAttributes();\n\t}\n\n\t// mergeAttributes, in contrast, only merges back on the\n\t// original attributes, not the events\n\tif ( dest.mergeAttributes ) {\n\t\tdest.mergeAttributes( src );\n\t}\n\n\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 fail to clone children inside object elements that use\n\t// the proprietary classid attribute value (rather than the type\n\t// attribute) to identify the type of content to display\n\tif ( nodeName === \"object\" ) {\n\t\tdest.outerHTML = src.outerHTML;\n\n\t} else if ( nodeName === \"input\" && (src.type === \"checkbox\" || src.type === \"radio\") ) {\n\t\t// IE6-8 fails to persist the checked state of a cloned checkbox\n\t\t// or radio button. Worse, IE6-7 fail to give the cloned element\n\t\t// a checked appearance if the defaultChecked value isn't also set\n\t\tif ( src.checked ) {\n\t\t\tdest.defaultChecked = dest.checked = src.checked;\n\t\t}\n\n\t\t// IE6-7 get confused and end up setting the value of a cloned\n\t\t// checkbox/radio button to an empty string instead of \"on\"\n\t\tif ( dest.value !== src.value ) {\n\t\t\tdest.value = src.value;\n\t\t}\n\n\t// IE6-8 fails to return the selected option to the default selected\n\t// state when cloning options\n\t} else if ( nodeName === \"option\" ) {\n\t\tdest.selected = src.defaultSelected;\n\n\t// IE6-8 fails to set the defaultValue to the correct value when\n\t// cloning other types of input fields\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n\n\t// Event data gets referenced instead of copied if the expando\n\t// gets copied too\n\tdest.removeAttribute( jQuery.expando );\n}\n\njQuery.buildFragment = function( args, nodes, scripts ) {\n\tvar fragment, cacheable, cacheresults,\n\t\tdoc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);\n\n\t// Only cache \"small\" (1/2 KB) HTML strings that are associated with the main document\n\t// Cloning options loses the selected state, so don't cache them\n\t// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment\n\t// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache\n\tif ( args.length === 1 && typeof args[0] === \"string\" && args[0].length < 512 && doc === document &&\n\t\targs[0].charAt(0) === \"<\" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {\n\n\t\tcacheable = true;\n\n\t\tcacheresults = jQuery.fragments[ args[0] ];\n\t\tif ( cacheresults && cacheresults !== 1 ) {\n\t\t\tfragment = cacheresults;\n\t\t}\n\t}\n\n\tif ( !fragment ) {\n\t\tfragment = doc.createDocumentFragment();\n\t\tjQuery.clean( args, doc, fragment, scripts );\n\t}\n\n\tif ( cacheable ) {\n\t\tjQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;\n\t}\n\n\treturn { fragment: fragment, cacheable: cacheable };\n};\n\njQuery.fragments = {};\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar ret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tparent = this.length === 1 && this[0].parentNode;\n\n\t\tif ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\n\t\t\tinsert[ original ]( this[0] );\n\t\t\treturn this;\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = insert.length; i < l; i++ ) {\n\t\t\t\tvar elems = (i > 0 ? this.clone(true) : this).get();\n\t\t\t\tjQuery( insert[i] )[ original ]( elems );\n\t\t\t\tret = ret.concat( elems );\n\t\t\t}\n\n\t\t\treturn this.pushStack( ret, name, insert.selector );\n\t\t}\n\t};\n});\n\nfunction getAll( elem ) {\n\tif ( \"getElementsByTagName\" in elem ) {\n\t\treturn elem.getElementsByTagName( \"*\" );\n\n\t} else if ( \"querySelectorAll\" in elem ) {\n\t\treturn elem.querySelectorAll( \"*\" );\n\n\t} else {\n\t\treturn [];\n\t}\n}\n\n// Used in clean, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( elem.type === \"checkbox\" || elem.type === \"radio\" ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n// Finds all inputs and passes them to fixDefaultChecked\nfunction findInputs( elem ) {\n\tif ( jQuery.nodeName( elem, \"input\" ) ) {\n\t\tfixDefaultChecked( elem );\n\t} else if ( elem.getElementsByTagName ) {\n\t\tjQuery.grep( elem.getElementsByTagName(\"input\"), fixDefaultChecked );\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar clone = elem.cloneNode(true),\n\t\t\t\tsrcElements,\n\t\t\t\tdestElements,\n\t\t\t\ti;\n\n\t\tif ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n\t\t\t// IE copies events bound via attachEvent when using cloneNode.\n\t\t\t// Calling detachEvent on the clone will also remove the events\n\t\t\t// from the original. In order to get around this, we use some\n\t\t\t// proprietary methods to clear the events. Thanks to MooTools\n\t\t\t// guys for this hotness.\n\n\t\t\tcloneFixAttributes( elem, clone );\n\n\t\t\t// Using Sizzle here is crazy slow, so we use getElementsByTagName\n\t\t\t// instead\n\t\t\tsrcElements = getAll( elem );\n\t\t\tdestElements = getAll( clone );\n\n\t\t\t// Weird iteration because IE will replace the length property\n\t\t\t// with an element if you are cloning the body and one of the\n\t\t\t// elements on the page has a name or id of \"length\"\n\t\t\tfor ( i = 0; srcElements[i]; ++i ) {\n\t\t\t\tcloneFixAttributes( srcElements[i], destElements[i] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tcloneCopyEvent( elem, clone );\n\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = getAll( elem );\n\t\t\t\tdestElements = getAll( clone );\n\n\t\t\t\tfor ( i = 0; srcElements[i]; ++i ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[i], destElements[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tclean: function( elems, context, fragment, scripts ) {\n\t\tvar checkScriptType;\n\n\t\tcontext = context || document;\n\n\t\t// !context.createElement fails in IE with an error but returns typeof 'object'\n\t\tif ( typeof context.createElement === \"undefined\" ) {\n\t\t\tcontext = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n\t\t}\n\n\t\tvar ret = [], j;\n\n\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( typeof elem === \"number\" ) {\n\t\t\t\telem += \"\";\n\t\t\t}\n\n\t\t\tif ( !elem ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Convert html string into DOM nodes\n\t\t\tif ( typeof elem === \"string\" ) {\n\t\t\t\tif ( !rhtml.test( elem ) ) {\n\t\t\t\t\telem = context.createTextNode( elem );\n\t\t\t\t} else {\n\t\t\t\t\t// Fix \"XHTML\"-style tags in all browsers\n\t\t\t\t\telem = elem.replace(rxhtmlTag, \"<$1></$2>\");\n\n\t\t\t\t\t// Trim whitespace, otherwise indexOf won't work as expected\n\t\t\t\t\tvar tag = (rtagName.exec( elem ) || [\"\", \"\"])[1].toLowerCase(),\n\t\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default,\n\t\t\t\t\t\tdepth = wrap[0],\n\t\t\t\t\t\tdiv = context.createElement(\"div\");\n\n\t\t\t\t\t// Go to html and back, then peel off extra wrappers\n\t\t\t\t\tdiv.innerHTML = wrap[1] + elem + wrap[2];\n\n\t\t\t\t\t// Move to the right depth\n\t\t\t\t\twhile ( depth-- ) {\n\t\t\t\t\t\tdiv = div.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\tvar hasBody = rtbody.test(elem),\n\t\t\t\t\t\t\ttbody = tag === \"table\" && !hasBody ?\n\t\t\t\t\t\t\t\tdiv.firstChild && div.firstChild.childNodes :\n\n\t\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\t\twrap[1] === \"<table>\" && !hasBody ?\n\t\t\t\t\t\t\t\t\tdiv.childNodes :\n\t\t\t\t\t\t\t\t\t[];\n\n\t\t\t\t\t\tfor ( j = tbody.length - 1; j >= 0 ; --j ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( tbody[ j ], \"tbody\" ) && !tbody[ j ].childNodes.length ) {\n\t\t\t\t\t\t\t\ttbody[ j ].parentNode.removeChild( tbody[ j ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// IE completely kills leading whitespace when innerHTML is used\n\t\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tdiv.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\telem = div.childNodes;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Resets defaultChecked for any radios and checkboxes\n\t\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\t\tvar len;\n\t\t\tif ( !jQuery.support.appendChecked ) {\n\t\t\t\tif ( elem[0] && typeof (len = elem.length) === \"number\" ) {\n\t\t\t\t\tfor ( j = 0; j < len; j++ ) {\n\t\t\t\t\t\tfindInputs( elem[j] );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfindInputs( elem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( elem.nodeType ) {\n\t\t\t\tret.push( elem );\n\t\t\t} else {\n\t\t\t\tret = jQuery.merge( ret, elem );\n\t\t\t}\n\t\t}\n\n\t\tif ( fragment ) {\n\t\t\tcheckScriptType = function( elem ) {\n\t\t\t\treturn !elem.type || rscriptType.test( elem.type );\n\t\t\t};\n\t\t\tfor ( i = 0; ret[i]; i++ ) {\n\t\t\t\tif ( scripts && jQuery.nodeName( ret[i], \"script\" ) && (!ret[i].type || ret[i].type.toLowerCase() === \"text/javascript\") ) {\n\t\t\t\t\tscripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );\n\n\t\t\t\t} else {\n\t\t\t\t\tif ( ret[i].nodeType === 1 ) {\n\t\t\t\t\t\tvar jsTags = jQuery.grep( ret[i].getElementsByTagName( \"script\" ), checkScriptType );\n\n\t\t\t\t\t\tret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );\n\t\t\t\t\t}\n\t\t\t\t\tfragment.appendChild( ret[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,\n\t\t\tdeleteExpando = jQuery.support.deleteExpando;\n\n\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tid = elem[ jQuery.expando ];\n\n\t\t\tif ( id ) {\n\t\t\t\tdata = cache[ id ] && cache[ id ][ internalKey ];\n\n\t\t\t\tif ( data && data.events ) {\n\t\t\t\t\tfor ( var type in data.events ) {\n\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Null the DOM reference to avoid IE6/7/8 leak (#7054)\n\t\t\t\t\tif ( data.handle ) {\n\t\t\t\t\t\tdata.handle.elem = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\tdelete elem[ jQuery.expando ];\n\n\t\t\t\t} else if ( elem.removeAttribute ) {\n\t\t\t\t\telem.removeAttribute( jQuery.expando );\n\t\t\t\t}\n\n\t\t\t\tdelete cache[ id ];\n\t\t\t}\n\t\t}\n\t}\n});\n\nfunction evalScript( i, elem ) {\n\tif ( elem.src ) {\n\t\tjQuery.ajax({\n\t\t\turl: elem.src,\n\t\t\tasync: false,\n\t\t\tdataType: \"script\"\n\t\t});\n\t} else {\n\t\tjQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || \"\" ).replace( rcleanScript, \"/*$0*/\" ) );\n\t}\n\n\tif ( elem.parentNode ) {\n\t\telem.parentNode.removeChild( elem );\n\t}\n}\n\n\n\n\nvar ralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity=([^)]*)/,\n\trdashAlpha = /-([a-z])/ig,\n\t// fixed for IE9, see #8346\n\trupper = /([A-Z]|^ms)/g,\n\trnumpx = /^-?\\d+(?:px)?$/i,\n\trnum = /^-?\\d/,\n\trrelNum = /^[+\\-]=/,\n\trrelNumFilter = /[^+\\-\\.\\de]+/g,\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssWidth = [ \"Left\", \"Right\" ],\n\tcssHeight = [ \"Top\", \"Bottom\" ],\n\tcurCSS,\n\n\tgetComputedStyle,\n\tcurrentStyle,\n\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn.css = function( name, value ) {\n\t// Setting 'undefined' is a no-op\n\tif ( arguments.length === 2 && value === undefined ) {\n\t\treturn this;\n\t}\n\n\treturn jQuery.access( this, name, value, true, function( elem, name, value ) {\n\t\treturn value !== undefined ?\n\t\t\tjQuery.style( elem, name, value ) :\n\t\t\tjQuery.css( elem, name );\n\t});\n};\n\njQuery.extend({\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\", \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\n\t\t\t\t} else {\n\t\t\t\t\treturn elem.style.opacity;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Exclude the following css properties to add px\n\tcssNumber: {\n\t\t\"zIndex\": true,\n\t\t\"fontWeight\": true,\n\t\t\"opacity\": true,\n\t\t\"zoom\": true,\n\t\t\"lineHeight\": true,\n\t\t\"widows\": true,\n\t\t\"orphans\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t// normalize float css property\n\t\t\"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, origName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style, hooks = jQuery.cssHooks[ origName ];\n\n\t\tname = jQuery.cssProps[ origName ] || origName;\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Make sure that NaN and null values aren't set. See: #7116\n\t\t\tif ( type === \"number\" && isNaN( value ) || value == null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && rrelNum.test( value ) ) {\n\t\t\t\tvalue = +value.replace( rrelNumFilter, \"\" ) + parseFloat( jQuery.css( elem, name ) );\n\t\t\t}\n\n\t\t\t// If a number was passed in, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {\n\t\t\t\t// Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n\t\t\t\t// Fixes bug #5509\n\t\t\t\ttry {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra ) {\n\t\tvar ret, hooks;\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.camelCase( name );\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tname = jQuery.cssProps[ name ] || name;\n\n\t\t// cssFloat needs a special treatment\n\t\tif ( name === \"cssFloat\" ) {\n\t\t\tname = \"float\";\n\t\t}\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {\n\t\t\treturn ret;\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\t} else if ( curCSS ) {\n\t\t\treturn curCSS( elem, name );\n\t\t}\n\t},\n\n\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback ) {\n\t\tvar old = {};\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( var name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tcallback.call( elem );\n\n\t\t// Revert the old values\n\t\tfor ( name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\t},\n\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rdashAlpha, fcamelCase );\n\t}\n});\n\n// DEPRECATED, Use jQuery.css() instead\njQuery.curCSS = jQuery.css;\n\njQuery.each([\"height\", \"width\"], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tvar val;\n\n\t\t\tif ( computed ) {\n\t\t\t\tif ( elem.offsetWidth !== 0 ) {\n\t\t\t\t\tval = getWH( elem, name, extra );\n\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\tval = getWH( elem, name, extra );\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif ( val <= 0 ) {\n\t\t\t\t\tval = curCSS( elem, name, name );\n\n\t\t\t\t\tif ( val === \"0px\" && currentStyle ) {\n\t\t\t\t\t\tval = currentStyle( elem, name, name );\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( val != null ) {\n\t\t\t\t\t\t// Should return \"auto\" instead of 0, use 0 for\n\t\t\t\t\t\t// temporary backwards-compat\n\t\t\t\t\t\treturn val === \"\" || val === \"auto\" ? \"0px\" : val;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( val < 0 || val == null ) {\n\t\t\t\t\tval = elem.style[ name ];\n\n\t\t\t\t\t// Should return \"auto\" instead of 0, use 0 for\n\t\t\t\t\t// temporary backwards-compat\n\t\t\t\t\treturn val === \"\" || val === \"auto\" ? \"0px\" : val;\n\t\t\t\t}\n\n\t\t\t\treturn typeof val === \"string\" ? val : val + \"px\";\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tif ( rnumpx.test( value ) ) {\n\t\t\t\t// ignore negative width and height values #1599\n\t\t\t\tvalue = parseFloat(value);\n\n\t\t\t\tif ( value >= 0 ) {\n\t\t\t\t\treturn value + \"px\";\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n});\n\nif ( !jQuery.support.opacity ) {\n\tjQuery.cssHooks.opacity = {\n\t\tget: function( elem, computed ) {\n\t\t\t// IE uses filters for opacity\n\t\t\treturn ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n\t\t\t\t( parseFloat( RegExp.$1 ) / 100 ) + \"\" :\n\t\t\t\tcomputed ? \"1\" : \"\";\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tvar style = elem.style,\n\t\t\t\tcurrentStyle = elem.currentStyle;\n\n\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t// Force it by setting the zoom level\n\t\t\tstyle.zoom = 1;\n\n\t\t\t// Set the alpha filter to set the opacity\n\t\t\tvar opacity = jQuery.isNaN( value ) ?\n\t\t\t\t\"\" :\n\t\t\t\t\"alpha(opacity=\" + value * 100 + \")\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n\t\t\tstyle.filter = ralpha.test( filter ) ?\n\t\t\t\tfilter.replace( ralpha, opacity ) :\n\t\t\t\tfilter + \" \" + opacity;\n\t\t}\n\t};\n}\n\njQuery(function() {\n\t// This hook cannot be added until DOM ready because the support test\n\t// for it is not run until after DOM ready\n\tif ( !jQuery.support.reliableMarginRight ) {\n\t\tjQuery.cssHooks.marginRight = {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\t\tvar ret;\n\t\t\t\tjQuery.swap( elem, { \"display\": \"inline-block\" }, function() {\n\t\t\t\t\tif ( computed ) {\n\t\t\t\t\t\tret = curCSS( elem, \"margin-right\", \"marginRight\" );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = elem.style.marginRight;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t};\n\t}\n});\n\nif ( document.defaultView && document.defaultView.getComputedStyle ) {\n\tgetComputedStyle = function( elem, name ) {\n\t\tvar ret, defaultView, computedStyle;\n\n\t\tname = name.replace( rupper, \"-$1\" ).toLowerCase();\n\n\t\tif ( !(defaultView = elem.ownerDocument.defaultView) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {\n\t\t\tret = computedStyle.getPropertyValue( name );\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nif ( document.documentElement.currentStyle ) {\n\tcurrentStyle = function( elem, name ) {\n\t\tvar left,\n\t\t\tret = elem.currentStyle && elem.currentStyle[ name ],\n\t\t\trsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],\n\t\t\tstyle = elem.style;\n\n\t\t// From the awesome hack by Dean Edwards\n\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t// If we're not dealing with a regular pixel number\n\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\tif ( !rnumpx.test( ret ) && rnum.test( ret ) ) {\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tif ( rsLeft ) {\n\t\t\t\telem.runtimeStyle.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : (ret || 0);\n\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.left = left;\n\t\t\tif ( rsLeft ) {\n\t\t\t\telem.runtimeStyle.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret === \"\" ? \"auto\" : ret;\n\t};\n}\n\ncurCSS = getComputedStyle || currentStyle;\n\nfunction getWH( elem, name, extra ) {\n\tvar which = name === \"width\" ? cssWidth : cssHeight,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight;\n\n\tif ( extra === \"border\" ) {\n\t\treturn val;\n\t}\n\n\tjQuery.each( which, function() {\n\t\tif ( !extra ) {\n\t\t\tval -= parseFloat(jQuery.css( elem, \"padding\" + this )) || 0;\n\t\t}\n\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += parseFloat(jQuery.css( elem, \"margin\" + this )) || 0;\n\n\t\t} else {\n\t\t\tval -= parseFloat(jQuery.css( elem, \"border\" + this + \"Width\" )) || 0;\n\t\t}\n\t});\n\n\treturn val;\n}\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\tvar width = elem.offsetWidth,\n\t\t\theight = elem.offsetHeight;\n\n\t\treturn (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, \"display\" )) === \"none\");\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\n\t};\n}\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trhash = /#.*$/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n\trinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app\\-storage|.+\\-extension|file|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trquery = /\\?/,\n\trscript = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\n\trselectTextarea = /^(?:select|textarea)/i,\n\trspacesAjax = /\\s+/,\n\trts = /([?&])_=[^&]*/,\n\trurl = /^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,\n\n\t// Keep a copy of the old load method\n\t_load = jQuery.fn.load,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Document location\n\tajaxLocation,\n\n\t// Document location segments\n\tajaxLocParts;\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\tvar dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),\n\t\t\t\ti = 0,\n\t\t\t\tlength = dataTypes.length,\n\t\t\t\tdataType,\n\t\t\t\tlist,\n\t\t\t\tplaceBefore;\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\tfor(; i < length; i++ ) {\n\t\t\t\tdataType = dataTypes[ i ];\n\t\t\t\t// We control if we're asked to add before\n\t\t\t\t// any existing element\n\t\t\t\tplaceBefore = /^\\+/.test( dataType );\n\t\t\t\tif ( placeBefore ) {\n\t\t\t\t\tdataType = dataType.substr( 1 ) || \"*\";\n\t\t\t\t}\n\t\t\t\tlist = structure[ dataType ] = structure[ dataType ] || [];\n\t\t\t\t// then we add to the structure accordingly\n\t\t\t\tlist[ placeBefore ? \"unshift\" : \"push\" ]( func );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,\n\t\tdataType /* internal */, inspected /* internal */ ) {\n\n\tdataType = dataType || options.dataTypes[ 0 ];\n\tinspected = inspected || {};\n\n\tinspected[ dataType ] = true;\n\n\tvar list = structure[ dataType ],\n\t\ti = 0,\n\t\tlength = list ? list.length : 0,\n\t\texecuteOnly = ( structure === prefilters ),\n\t\tselection;\n\n\tfor(; i < length && ( executeOnly || !selection ); i++ ) {\n\t\tselection = list[ i ]( options, originalOptions, jqXHR );\n\t\t// If we got redirected to another dataType\n\t\t// we try there if executing only and not done already\n\t\tif ( typeof selection === \"string\" ) {\n\t\t\tif ( !executeOnly || inspected[ selection ] ) {\n\t\t\t\tselection = undefined;\n\t\t\t} else {\n\t\t\t\toptions.dataTypes.unshift( selection );\n\t\t\t\tselection = inspectPrefiltersOrTransports(\n\t\t\t\t\t\tstructure, options, originalOptions, jqXHR, selection, inspected );\n\t\t\t}\n\t\t}\n\t}\n\t// If we're only executing or nothing was selected\n\t// we try the catchall dataType if not done already\n\tif ( ( executeOnly || !selection ) && !inspected[ \"*\" ] ) {\n\t\tselection = inspectPrefiltersOrTransports(\n\t\t\t\tstructure, options, originalOptions, jqXHR, \"*\", inspected );\n\t}\n\t// unnecessary when only executing (prefilters)\n\t// but it'll be ignored by the caller in that case\n\treturn selection;\n}\n\njQuery.fn.extend({\n\tload: function( url, params, callback ) {\n\t\tif ( typeof url !== \"string\" && _load ) {\n\t\t\treturn _load.apply( this, arguments );\n\n\t\t// Don't do a request if no elements are being requested\n\t\t} else if ( !this.length ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar off = url.indexOf( \" \" );\n\t\tif ( off >= 0 ) {\n\t\t\tvar selector = url.slice( off, url.length );\n\t\t\turl = url.slice( 0, off );\n\t\t}\n\n\t\t// Default to a GET request\n\t\tvar type = \"GET\";\n\n\t\t// If the second parameter was provided\n\t\tif ( params ) {\n\t\t\t// If it's a function\n\t\t\tif ( jQuery.isFunction( params ) ) {\n\t\t\t\t// We assume that it's the callback\n\t\t\t\tcallback = params;\n\t\t\t\tparams = undefined;\n\n\t\t\t// Otherwise, build a param string\n\t\t\t} else if ( typeof params === \"object\" ) {\n\t\t\t\tparams = jQuery.param( params, jQuery.ajaxSettings.traditional );\n\t\t\t\ttype = \"POST\";\n\t\t\t}\n\t\t}\n\n\t\tvar self = this;\n\n\t\t// Request the remote document\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params,\n\t\t\t// Complete callback (responseText is used internally)\n\t\t\tcomplete: function( jqXHR, status, responseText ) {\n\t\t\t\t// Store the response as specified by the jqXHR object\n\t\t\t\tresponseText = jqXHR.responseText;\n\t\t\t\t// If successful, inject the HTML into all the matched elements\n\t\t\t\tif ( jqXHR.isResolved() ) {\n\t\t\t\t\t// #4825: Get the actual response in case\n\t\t\t\t\t// a dataFilter is present in ajaxSettings\n\t\t\t\t\tjqXHR.done(function( r ) {\n\t\t\t\t\t\tresponseText = r;\n\t\t\t\t\t});\n\t\t\t\t\t// See if a selector was specified\n\t\t\t\t\tself.html( selector ?\n\t\t\t\t\t\t// Create a dummy div to hold the results\n\t\t\t\t\t\tjQuery(\"<div>\")\n\t\t\t\t\t\t\t// inject the contents of the document in, removing the scripts\n\t\t\t\t\t\t\t// to avoid any 'Permission Denied' errors in IE\n\t\t\t\t\t\t\t.append(responseText.replace(rscript, \"\"))\n\n\t\t\t\t\t\t\t// Locate the specified elements\n\t\t\t\t\t\t\t.find(selector) :\n\n\t\t\t\t\t\t// If not, just inject the full result\n\t\t\t\t\t\tresponseText );\n\t\t\t\t}\n\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tself.each( callback, [ responseText, status, jqXHR ] );\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t},\n\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\n\tserializeArray: function() {\n\t\treturn this.map(function(){\n\t\t\treturn this.elements ? jQuery.makeArray( this.elements ) : this;\n\t\t})\n\t\t.filter(function(){\n\t\t\treturn this.name && !this.disabled &&\n\t\t\t\t( this.checked || rselectTextarea.test( this.nodeName ) ||\n\t\t\t\t\trinput.test( this.type ) );\n\t\t})\n\t\t.map(function( i, elem ){\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val, i ){\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( \"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split( \" \" ), function( i, o ){\n\tjQuery.fn[ o ] = function( f ){\n\t\treturn this.bind( o, f );\n\t};\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\ttype: method,\n\t\t\turl: url,\n\t\t\tdata: data,\n\t\t\tsuccess: callback,\n\t\t\tdataType: type\n\t\t});\n\t};\n});\n\njQuery.extend({\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function ( target, settings ) {\n\t\tif ( !settings ) {\n\t\t\t// Only one parameter, we extend ajaxSettings\n\t\t\tsettings = target;\n\t\t\ttarget = jQuery.extend( true, jQuery.ajaxSettings, settings );\n\t\t} else {\n\t\t\t// target was provided, we extend into it\n\t\t\tjQuery.extend( true, target, jQuery.ajaxSettings, settings );\n\t\t}\n\t\t// Flatten fields we don't want deep extended\n\t\tfor( var field in { context: 1, url: 1 } ) {\n\t\t\tif ( field in settings ) {\n\t\t\t\ttarget[ field ] = settings[ field ];\n\t\t\t} else if( field in jQuery.ajaxSettings ) {\n\t\t\t\ttarget[ field ] = jQuery.ajaxSettings[ field ];\n\t\t\t}\n\t\t}\n\t\treturn target;\n\t},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\ttype: \"GET\",\n\t\tcontentType: \"application/x-www-form-urlencoded\",\n\t\tprocessData: true,\n\t\tasync: true,\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\thtml: \"text/html\",\n\t\t\ttext: \"text/plain\",\n\t\t\tjson: \"application/json, text/javascript\",\n\t\t\t\"*\": \"*/*\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\"\n\t\t},\n\n\t\t// List of data converters\n\t\t// 1) key format is \"source_type destination_type\" (a single space in-between)\n\t\t// 2) the catchall symbol \"*\" can be used for source_type\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": window.String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t}\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar // Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events\n\t\t\t// It's the callbackContext if one was provided in the options\n\t\t\t// and if it's a DOM node or a jQuery collection\n\t\t\tglobalEventContext = callbackContext !== s &&\n\t\t\t\t( callbackContext.nodeType || callbackContext instanceof jQuery ) ?\n\t\t\t\t\t\tjQuery( callbackContext ) : jQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery._Deferred(),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// ifModified key\n\t\t\tifModifiedKey,\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// transport\n\t\t\ttransport,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match === undefined ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tstatusText = statusText || \"abort\";\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( statusText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, statusText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Callback for when everything is done\n\t\t// It is defined here because jslint complains if it is declared\n\t\t// at the end of the function (which would be more logical and readable)\n\t\tfunction done( status, statusText, responses, headers ) {\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status ? 4 : 0;\n\n\t\t\tvar isSuccess,\n\t\t\t\tsuccess,\n\t\t\t\terror,\n\t\t\t\tresponse = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,\n\t\t\t\tlastModified,\n\t\t\t\tetag;\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( status >= 200 && status < 300 || status === 304 ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\n\t\t\t\t\tif ( ( lastModified = jqXHR.getResponseHeader( \"Last-Modified\" ) ) ) {\n\t\t\t\t\t\tjQuery.lastModified[ ifModifiedKey ] = lastModified;\n\t\t\t\t\t}\n\t\t\t\t\tif ( ( etag = jqXHR.getResponseHeader( \"Etag\" ) ) ) {\n\t\t\t\t\t\tjQuery.etag[ ifModifiedKey ] = etag;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If not modified\n\t\t\t\tif ( status === 304 ) {\n\n\t\t\t\t\tstatusText = \"notmodified\";\n\t\t\t\t\tisSuccess = true;\n\n\t\t\t\t// If we have data\n\t\t\t\t} else {\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsuccess = ajaxConvert( s, response );\n\t\t\t\t\t\tstatusText = \"success\";\n\t\t\t\t\t\tisSuccess = true;\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t// We have a parsererror\n\t\t\t\t\t\tstatusText = \"parsererror\";\n\t\t\t\t\t\terror = e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif( !statusText || status ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = statusText;\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajax\" + ( isSuccess ? \"Success\" : \"Error\" ),\n\t\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\t\tjqXHR.complete = completeDeferred.done;\n\n\t\t// Status-dependent callbacks\n\t\tjqXHR.statusCode = function( map ) {\n\t\t\tif ( map ) {\n\t\t\t\tvar tmp;\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tfor( tmp in map ) {\n\t\t\t\t\t\tstatusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttmp = map[ jqXHR.status ];\n\t\t\t\t\tjqXHR.then( tmp, tmp );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this;\n\t\t};\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().split( rspacesAjax );\n\n\t\t// Determine if a cross-domain request is in order\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefiler, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\tfireGlobals = s.global;\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.data;\n\t\t\t}\n\n\t\t\t// Get ifModifiedKey before adding the anti-cache parameter\n\t\t\tifModifiedKey = s.url;\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\n\t\t\t\tvar ts = jQuery.now(),\n\t\t\t\t\t// try replacing _= if it is there\n\t\t\t\t\tret = s.url.replace( rts, \"$1_=\" + ts );\n\n\t\t\t\t// if nothing was replaced, add timestamp to the end\n\t\t\t\ts.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? \"&\" : \"?\" ) + \"_=\" + ts : \"\" );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tifModifiedKey = ifModifiedKey || s.url;\n\t\t\tif ( jQuery.lastModified[ ifModifiedKey ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ ifModifiedKey ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ ifModifiedKey ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ ifModifiedKey ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", */*; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t\t// Abort if not done already\n\t\t\t\tjqXHR.abort();\n\t\t\t\treturn false;\n\n\t\t}\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout( function(){\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch (e) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( status < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.error( e );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\t// Serialize an array of form elements or a set of\n\t// key/values into a query string\n\tparam: function( a, traditional ) {\n\t\tvar s = [],\n\t\t\tadd = function( key, value ) {\n\t\t\t\t// If value is a function, invoke it and return its value\n\t\t\t\tvalue = jQuery.isFunction( value ) ? value() : value;\n\t\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t\t};\n\n\t\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\t\tif ( traditional === undefined ) {\n\t\t\ttraditional = jQuery.ajaxSettings.traditional;\n\t\t}\n\n\t\t// If an array was passed in, assume that it is an array of form elements.\n\t\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t\t// Serialize the form elements\n\t\t\tjQuery.each( a, function() {\n\t\t\t\tadd( this.name, this.value );\n\t\t\t});\n\n\t\t} else {\n\t\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t\t// did it), otherwise encode params recursively.\n\t\t\tfor ( var prefix in a ) {\n\t\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t\t}\n\t\t}\n\n\t\t// Return the resulting serialization\n\t\treturn s.join( \"&\" ).replace( r20, \"+\" );\n\t}\n});\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// If array item is non-scalar (array or object), encode its\n\t\t\t\t// numeric index to resolve deserialization ambiguity issues.\n\t\t\t\t// Note that rack (as of 1.0.0) can't currently deserialize\n\t\t\t\t// nested arrays properly, and attempting to do so may cause\n\t\t\t\t// a server error. Possible fixes are to modify rack's\n\t\t\t\t// deserialization algorithm or to provide an option or flag\n\t\t\t\t// to force array serialization to be shallow.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" || jQuery.isArray(v) ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && obj != null && typeof obj === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( var name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// This is still on the jQuery object... for now\n// Want to move this to jQuery.ajax some day\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {}\n\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar contents = s.contents,\n\t\tdataTypes = s.dataTypes,\n\t\tresponseFields = s.responseFields,\n\t\tct,\n\t\ttype,\n\t\tfinalDataType,\n\t\tfirstDataType;\n\n\t// Fill responseXXX fields\n\tfor( type in responseFields ) {\n\t\tif ( type in responses ) {\n\t\t\tjqXHR[ responseFields[type] ] = responses[ type ];\n\t\t}\n\t}\n\n\t// Remove auto dataType and get content-type in the process\n\twhile( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"content-type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n// Chain conversions given the request and the original response\nfunction ajaxConvert( s, response ) {\n\n\t// Apply the dataFilter if provided\n\tif ( s.dataFilter ) {\n\t\tresponse = s.dataFilter( response, s.dataType );\n\t}\n\n\tvar dataTypes = s.dataTypes,\n\t\tconverters = {},\n\t\ti,\n\t\tkey,\n\t\tlength = dataTypes.length,\n\t\ttmp,\n\t\t// Current and previous dataTypes\n\t\tcurrent = dataTypes[ 0 ],\n\t\tprev,\n\t\t// Conversion expression\n\t\tconversion,\n\t\t// Conversion function\n\t\tconv,\n\t\t// Conversion functions (transitive conversion)\n\t\tconv1,\n\t\tconv2;\n\n\t// For each dataType in the chain\n\tfor( i = 1; i < length; i++ ) {\n\n\t\t// Create converters map\n\t\t// with lowercased keys\n\t\tif ( i === 1 ) {\n\t\t\tfor( key in s.converters ) {\n\t\t\t\tif( typeof key === \"string\" ) {\n\t\t\t\t\tconverters[ key.toLowerCase() ] = s.converters[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Get the dataTypes\n\t\tprev = current;\n\t\tcurrent = dataTypes[ i ];\n\n\t\t// If current is auto dataType, update it to prev\n\t\tif( current === \"*\" ) {\n\t\t\tcurrent = prev;\n\t\t// If no auto and dataTypes are actually different\n\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t// Get the converter\n\t\t\tconversion = prev + \" \" + current;\n\t\t\tconv = converters[ conversion ] || converters[ \"* \" + current ];\n\n\t\t\t// If there is no direct converter, search transitively\n\t\t\tif ( !conv ) {\n\t\t\t\tconv2 = undefined;\n\t\t\t\tfor( conv1 in converters ) {\n\t\t\t\t\ttmp = conv1.split( \" \" );\n\t\t\t\t\tif ( tmp[ 0 ] === prev || tmp[ 0 ] === \"*\" ) {\n\t\t\t\t\t\tconv2 = converters[ tmp[1] + \" \" + current ];\n\t\t\t\t\t\tif ( conv2 ) {\n\t\t\t\t\t\t\tconv1 = converters[ conv1 ];\n\t\t\t\t\t\t\tif ( conv1 === true ) {\n\t\t\t\t\t\t\t\tconv = conv2;\n\t\t\t\t\t\t\t} else if ( conv2 === true ) {\n\t\t\t\t\t\t\t\tconv = conv1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If we found no converter, dispatch an error\n\t\t\tif ( !( conv || conv2 ) ) {\n\t\t\t\tjQuery.error( \"No conversion from \" + conversion.replace(\" \",\" to \") );\n\t\t\t}\n\t\t\t// If found converter is not an equivalence\n\t\t\tif ( conv !== true ) {\n\t\t\t\t// Convert with 1 or 2 converters accordingly\n\t\t\t\tresponse = conv ? conv( response ) : conv2( conv1(response) );\n\t\t\t}\n\t\t}\n\t}\n\treturn response;\n}\n\n\n\n\nvar jsc = jQuery.now(),\n\tjsre = /(\\=)\\?(&|$)|\\?\\?/i;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\treturn jQuery.expando + \"_\" + ( jsc++ );\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar inspectData = s.contentType === \"application/x-www-form-urlencoded\" &&\n\t\t( typeof s.data === \"string\" );\n\n\tif ( s.dataTypes[ 0 ] === \"jsonp\" ||\n\t\ts.jsonp !== false && ( jsre.test( s.url ) ||\n\t\t\t\tinspectData && jsre.test( s.data ) ) ) {\n\n\t\tvar responseContainer,\n\t\t\tjsonpCallback = s.jsonpCallback =\n\t\t\t\tjQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,\n\t\t\tprevious = window[ jsonpCallback ],\n\t\t\turl = s.url,\n\t\t\tdata = s.data,\n\t\t\treplace = \"$1\" + jsonpCallback + \"$2\";\n\n\t\tif ( s.jsonp !== false ) {\n\t\t\turl = url.replace( jsre, replace );\n\t\t\tif ( s.url === url ) {\n\t\t\t\tif ( inspectData ) {\n\t\t\t\t\tdata = data.replace( jsre, replace );\n\t\t\t\t}\n\t\t\t\tif ( s.data === data ) {\n\t\t\t\t\t// Add callback manually\n\t\t\t\t\turl += (/\\?/.test( url ) ? \"&\" : \"?\") + s.jsonp + \"=\" + jsonpCallback;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ts.url = url;\n\t\ts.data = data;\n\n\t\t// Install callback\n\t\twindow[ jsonpCallback ] = function( response ) {\n\t\t\tresponseContainer = [ response ];\n\t\t};\n\n\t\t// Clean-up function\n\t\tjqXHR.always(function() {\n\t\t\t// Set callback back to previous value\n\t\t\twindow[ jsonpCallback ] = previous;\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( previous ) ) {\n\t\t\t\twindow[ jsonpCallback ]( responseContainer[ 0 ] );\n\t\t\t}\n\t\t});\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( jsonpCallback + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /javascript|ecmascript/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and global\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t\ts.global = false;\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\n\t\tvar script,\n\t\t\thead = document.head || document.getElementsByTagName( \"head\" )[0] || document.documentElement;\n\n\t\treturn {\n\n\t\t\tsend: function( _, callback ) {\n\n\t\t\t\tscript = document.createElement( \"script\" );\n\n\t\t\t\tscript.async = \"async\";\n\n\t\t\t\tif ( s.scriptCharset ) {\n\t\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t\t}\n\n\t\t\t\tscript.src = s.url;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function( _, isAbort ) {\n\n\t\t\t\t\tif ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\n\t\t\t\t\t\t// Remove the script\n\t\t\t\t\t\tif ( head && script.parentNode ) {\n\t\t\t\t\t\t\thead.removeChild( script );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Dereference the script\n\t\t\t\t\t\tscript = undefined;\n\n\t\t\t\t\t\t// Callback if not abort\n\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\tcallback( 200, \"success\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t// Use insertBefore instead of appendChild  to circumvent an IE6 bug.\n\t\t\t\t// This arises when a base node is used (#2709 and #4378).\n\t\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( script ) {\n\t\t\t\t\tscript.onload( 0, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar // #5280: Internet Explorer will keep connections alive if we don't abort on unload\n\txhrOnUnloadAbort = window.ActiveXObject ? function() {\n\t\t// Abort all pending requests\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( 0, 1 );\n\t\t}\n\t} : false,\n\txhrId = 0,\n\txhrCallbacks;\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch( e ) {}\n}\n\nfunction createActiveXHR() {\n\ttry {\n\t\treturn new window.ActiveXObject( \"Microsoft.XMLHTTP\" );\n\t} catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n\t/* Microsoft failed to properly\n\t * implement the XMLHttpRequest in IE7 (can't request local files),\n\t * so we use the ActiveXObject when it is available\n\t * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n\t * we need a fallback.\n\t */\n\tfunction() {\n\t\treturn !this.isLocal && createStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\n// Determine support properties\n(function( xhr ) {\n\tjQuery.extend( jQuery.support, {\n\t\tajax: !!xhr,\n\t\tcors: !!xhr && ( \"withCredentials\" in xhr )\n\t});\n})( jQuery.ajaxSettings.xhr() );\n\n// Create transport if the browser can provide an xhr\nif ( jQuery.support.ajax ) {\n\n\tjQuery.ajaxTransport(function( s ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !s.crossDomain || jQuery.support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\n\t\t\t\t\t// Get a new xhr\n\t\t\t\t\tvar xhr = s.xhr(),\n\t\t\t\t\t\thandle,\n\t\t\t\t\t\ti;\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\t\t\t\tif ( s.username ) {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async, s.username, s.password );\n\t\t\t\t\t} else {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( s.xhrFields ) {\n\t\t\t\t\t\tfor ( i in s.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = s.xhrFields[ i ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Override mime type if needed\n\t\t\t\t\tif ( s.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( s.mimeType );\n\t\t\t\t\t}\n\n\t\t\t\t\t// X-Requested-With header\n\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\t\tif ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch( _ ) {}\n\n\t\t\t\t\t// Do send the request\n\t\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\t\txhr.send( ( s.hasContent && s.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\n\t\t\t\t\t\tvar status,\n\t\t\t\t\t\t\tstatusText,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\tresponses,\n\t\t\t\t\t\t\txml;\n\n\t\t\t\t\t\t// Firefox throws exceptions when accessing properties\n\t\t\t\t\t\t// of an xhr when a network error occured\n\t\t\t\t\t\t// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n\t\t\t\t\t\t\t\t// Only called once\n\t\t\t\t\t\t\t\tcallback = undefined;\n\n\t\t\t\t\t\t\t\t// Do not keep as active anymore\n\t\t\t\t\t\t\t\tif ( handle ) {\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t\t\t\tdelete xhrCallbacks[ handle ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If it's an abort\n\t\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\t\t// Abort it manually if needed\n\t\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tstatus = xhr.status;\n\t\t\t\t\t\t\t\t\tresponseHeaders = xhr.getAllResponseHeaders();\n\t\t\t\t\t\t\t\t\tresponses = {};\n\t\t\t\t\t\t\t\t\txml = xhr.responseXML;\n\n\t\t\t\t\t\t\t\t\t// Construct response list\n\t\t\t\t\t\t\t\t\tif ( xml && xml.documentElement /* #4958 */ ) {\n\t\t\t\t\t\t\t\t\t\tresponses.xml = xml;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\n\t\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t\t} catch( e ) {\n\t\t\t\t\t\t\t\t\t\t// We normalize with Webkit giving an empty statusText\n\t\t\t\t\t\t\t\t\t\tstatusText = \"\";\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\t\t\t\t\t\t\t\t\t// If the request is local and we have data: assume a success\n\t\t\t\t\t\t\t\t\t// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\t\tif ( !status && s.isLocal && !s.crossDomain ) {\n\t\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\t\t\t\t\t\t\t\t\t// IE - #1450: sometimes returns 1223 when it should be 204\n\t\t\t\t\t\t\t\t\t} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\t\tstatus = 204;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch( firefoxAccessException ) {\n\t\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\t\tcomplete( -1, firefoxAccessException );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Call complete if needed\n\t\t\t\t\t\tif ( responses ) {\n\t\t\t\t\t\t\tcomplete( status, statusText, responses, responseHeaders );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\t// if we're in sync mode or it's in cache\n\t\t\t\t\t// and has been retrieved directly (IE6 & IE7)\n\t\t\t\t\t// we need to manually fire the callback\n\t\t\t\t\tif ( !s.async || xhr.readyState === 4 ) {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandle = ++xhrId;\n\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t// Create the active xhrs callbacks list if needed\n\t\t\t\t\t\t\t// and attach the unload handler\n\t\t\t\t\t\t\tif ( !xhrCallbacks ) {\n\t\t\t\t\t\t\t\txhrCallbacks = {};\n\t\t\t\t\t\t\t\tjQuery( window ).unload( xhrOnUnloadAbort );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Add to list of active xhrs callbacks\n\t\t\t\t\t\t\txhrCallbacks[ handle ] = callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\txhr.onreadystatechange = callback;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tabort: function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback(0,1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\n\n\n\n\nvar elemdisplay = {},\n\tiframe, iframeDoc,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = /^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,\n\ttimerId,\n\tfxAttrs = [\n\t\t// height animations\n\t\t[ \"height\", \"marginTop\", \"marginBottom\", \"paddingTop\", \"paddingBottom\" ],\n\t\t// width animations\n\t\t[ \"width\", \"marginLeft\", \"marginRight\", \"paddingLeft\", \"paddingRight\" ],\n\t\t// opacity animations\n\t\t[ \"opacity\" ]\n\t],\n\tfxNow,\n\trequestAnimationFrame = window.webkitRequestAnimationFrame ||\n\t    window.mozRequestAnimationFrame ||\n\t    window.oRequestAnimationFrame;\n\njQuery.fn.extend({\n\tshow: function( speed, easing, callback ) {\n\t\tvar elem, display;\n\n\t\tif ( speed || speed === 0 ) {\n\t\t\treturn this.animate( genFx(\"show\", 3), speed, easing, callback);\n\n\t\t} else {\n\t\t\tfor ( var i = 0, j = this.length; i < j; i++ ) {\n\t\t\t\telem = this[i];\n\n\t\t\t\tif ( elem.style ) {\n\t\t\t\t\tdisplay = elem.style.display;\n\n\t\t\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t\t\t// being hidden by cascaded rules or not\n\t\t\t\t\tif ( !jQuery._data(elem, \"olddisplay\") && display === \"none\" ) {\n\t\t\t\t\t\tdisplay = elem.style.display = \"\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set elements which have been overridden with display: none\n\t\t\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t\t\t// for such an element\n\t\t\t\t\tif ( display === \"\" && jQuery.css( elem, \"display\" ) === \"none\" ) {\n\t\t\t\t\t\tjQuery._data(elem, \"olddisplay\", defaultDisplay(elem.nodeName));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of most of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( i = 0; i < j; i++ ) {\n\t\t\t\telem = this[i];\n\n\t\t\t\tif ( elem.style ) {\n\t\t\t\t\tdisplay = elem.style.display;\n\n\t\t\t\t\tif ( display === \"\" || display === \"none\" ) {\n\t\t\t\t\t\telem.style.display = jQuery._data(elem, \"olddisplay\") || \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\thide: function( speed, easing, callback ) {\n\t\tif ( speed || speed === 0 ) {\n\t\t\treturn this.animate( genFx(\"hide\", 3), speed, easing, callback);\n\n\t\t} else {\n\t\t\tfor ( var i = 0, j = this.length; i < j; i++ ) {\n\t\t\t\tif ( this[i].style ) {\n\t\t\t\t\tvar display = jQuery.css( this[i], \"display\" );\n\n\t\t\t\t\tif ( display !== \"none\" && !jQuery._data( this[i], \"olddisplay\" ) ) {\n\t\t\t\t\t\tjQuery._data( this[i], \"olddisplay\", display );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( i = 0; i < j; i++ ) {\n\t\t\t\tif ( this[i].style ) {\n\t\t\t\t\tthis[i].style.display = \"none\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t// Save the old toggle function\n\t_toggle: jQuery.fn.toggle,\n\n\ttoggle: function( fn, fn2, callback ) {\n\t\tvar bool = typeof fn === \"boolean\";\n\n\t\tif ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n\t\t\tthis._toggle.apply( this, arguments );\n\n\t\t} else if ( fn == null || bool ) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar state = bool ? fn : jQuery(this).is(\":hidden\");\n\t\t\t\tjQuery(this)[ state ? \"show\" : \"hide\" ]();\n\t\t\t});\n\n\t\t} else {\n\t\t\tthis.animate(genFx(\"toggle\", 3), fn, fn2, callback);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tfadeTo: function( speed, to, easing, callback ) {\n\t\treturn this.filter(\":hidden\").css(\"opacity\", 0).show().end()\n\t\t\t\t\t.animate({opacity: to}, speed, easing, callback);\n\t},\n\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar optall = jQuery.speed(speed, easing, callback);\n\n\t\tif ( jQuery.isEmptyObject( prop ) ) {\n\t\t\treturn this.each( optall.complete, [ false ] );\n\t\t}\n\n\t\t// Do not change referenced properties as per-property easing will be lost\n\t\tprop = jQuery.extend( {}, prop );\n\n\t\treturn this[ optall.queue === false ? \"each\" : \"queue\" ](function() {\n\t\t\t// XXX 'this' does not always have a nodeName when running the\n\t\t\t// test suite\n\n\t\t\tif ( optall.queue === false ) {\n\t\t\t\tjQuery._mark( this );\n\t\t\t}\n\n\t\t\tvar opt = jQuery.extend( {}, optall ),\n\t\t\t\tisElement = this.nodeType === 1,\n\t\t\t\thidden = isElement && jQuery(this).is(\":hidden\"),\n\t\t\t\tname, val, p,\n\t\t\t\tdisplay, e,\n\t\t\t\tparts, start, end, unit;\n\n\t\t\t// will store per property easing and be used to determine when an animation is complete\n\t\t\topt.animatedProperties = {};\n\n\t\t\tfor ( p in prop ) {\n\n\t\t\t\t// property name normalization\n\t\t\t\tname = jQuery.camelCase( p );\n\t\t\t\tif ( p !== name ) {\n\t\t\t\t\tprop[ name ] = prop[ p ];\n\t\t\t\t\tdelete prop[ p ];\n\t\t\t\t}\n\n\t\t\t\tval = prop[ name ];\n\n\t\t\t\t// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)\n\t\t\t\tif ( jQuery.isArray( val ) ) {\n\t\t\t\t\topt.animatedProperties[ name ] = val[ 1 ];\n\t\t\t\t\tval = prop[ name ] = val[ 0 ];\n\t\t\t\t} else {\n\t\t\t\t\topt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';\n\t\t\t\t}\n\n\t\t\t\tif ( val === \"hide\" && hidden || val === \"show\" && !hidden ) {\n\t\t\t\t\treturn opt.complete.call( this );\n\t\t\t\t}\n\n\t\t\t\tif ( isElement && ( name === \"height\" || name === \"width\" ) ) {\n\t\t\t\t\t// Make sure that nothing sneaks out\n\t\t\t\t\t// Record all 3 overflow attributes because IE does not\n\t\t\t\t\t// change the overflow attribute when overflowX and\n\t\t\t\t\t// overflowY are set to the same value\n\t\t\t\t\topt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];\n\n\t\t\t\t\t// Set display property to inline-block for height/width\n\t\t\t\t\t// animations on inline elements that are having width/height\n\t\t\t\t\t// animated\n\t\t\t\t\tif ( jQuery.css( this, \"display\" ) === \"inline\" &&\n\t\t\t\t\t\t\tjQuery.css( this, \"float\" ) === \"none\" ) {\n\t\t\t\t\t\tif ( !jQuery.support.inlineBlockNeedsLayout ) {\n\t\t\t\t\t\t\tthis.style.display = \"inline-block\";\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdisplay = defaultDisplay( this.nodeName );\n\n\t\t\t\t\t\t\t// inline-level elements accept inline-block;\n\t\t\t\t\t\t\t// block-level elements need to be inline with layout\n\t\t\t\t\t\t\tif ( display === \"inline\" ) {\n\t\t\t\t\t\t\t\tthis.style.display = \"inline-block\";\n\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.style.display = \"inline\";\n\t\t\t\t\t\t\t\tthis.style.zoom = 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( opt.overflow != null ) {\n\t\t\t\tthis.style.overflow = \"hidden\";\n\t\t\t}\n\n\t\t\tfor ( p in prop ) {\n\t\t\t\te = new jQuery.fx( this, opt, p );\n\t\t\t\tval = prop[ p ];\n\n\t\t\t\tif ( rfxtypes.test(val) ) {\n\t\t\t\t\te[ val === \"toggle\" ? hidden ? \"show\" : \"hide\" : val ]();\n\n\t\t\t\t} else {\n\t\t\t\t\tparts = rfxnum.exec( val );\n\t\t\t\t\tstart = e.cur();\n\n\t\t\t\t\tif ( parts ) {\n\t\t\t\t\t\tend = parseFloat( parts[2] );\n\t\t\t\t\t\tunit = parts[3] || ( jQuery.cssNumber[ p ] ? \"\" : \"px\" );\n\n\t\t\t\t\t\t// We need to compute starting value\n\t\t\t\t\t\tif ( unit !== \"px\" ) {\n\t\t\t\t\t\t\tjQuery.style( this, p, (end || 1) + unit);\n\t\t\t\t\t\t\tstart = ((end || 1) / e.cur()) * start;\n\t\t\t\t\t\t\tjQuery.style( this, p, start + unit);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\t\t\tif ( parts[1] ) {\n\t\t\t\t\t\t\tend = ( (parts[ 1 ] === \"-=\" ? -1 : 1) * end ) + start;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\te.custom( start, end, unit );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\te.custom( start, val, \"\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// For JS strict compliance\n\t\t\treturn true;\n\t\t});\n\t},\n\n\tstop: function( clearQueue, gotoEnd ) {\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue([]);\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\tvar timers = jQuery.timers,\n\t\t\t\ti = timers.length;\n\t\t\t// clear marker counters if we know they won't be\n\t\t\tif ( !gotoEnd ) {\n\t\t\t\tjQuery._unmark( true, this );\n\t\t\t}\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( timers[i].elem === this ) {\n\t\t\t\t\tif (gotoEnd) {\n\t\t\t\t\t\t// force the next step to be the last\n\t\t\t\t\t\ttimers[i](true);\n\t\t\t\t\t}\n\n\t\t\t\t\ttimers.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// start the next in the queue if the last step wasn't forced\n\t\tif ( !gotoEnd ) {\n\t\t\tthis.dequeue();\n\t\t}\n\n\t\treturn this;\n\t}\n\n});\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout( clearFxNow, 0 );\n\treturn ( fxNow = jQuery.now() );\n}\n\nfunction clearFxNow() {\n\tfxNow = undefined;\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, num ) {\n\tvar obj = {};\n\n\tjQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {\n\t\tobj[ this ] = type;\n\t});\n\n\treturn obj;\n}\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\", 1),\n\tslideUp: genFx(\"hide\", 1),\n\tslideToggle: genFx(\"toggle\", 1),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.extend({\n\tspeed: function( speed, easing, fn ) {\n\t\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend({}, speed) : {\n\t\t\tcomplete: fn || !fn && easing ||\n\t\t\t\tjQuery.isFunction( speed ) && speed,\n\t\t\tduration: speed,\n\t\t\teasing: fn && easing || easing && !jQuery.isFunction(easing) && easing\n\t\t};\n\n\t\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;\n\n\t\t// Queueing\n\t\topt.old = opt.complete;\n\t\topt.complete = function( noUnmark ) {\n\t\t\tif ( opt.queue !== false ) {\n\t\t\t\tjQuery.dequeue( this );\n\t\t\t} else if ( noUnmark !== false ) {\n\t\t\t\tjQuery._unmark( this );\n\t\t\t}\n\n\t\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\t\topt.old.call( this );\n\t\t\t}\n\t\t};\n\n\t\treturn opt;\n\t},\n\n\teasing: {\n\t\tlinear: function( p, n, firstNum, diff ) {\n\t\t\treturn firstNum + diff * p;\n\t\t},\n\t\tswing: function( p, n, firstNum, diff ) {\n\t\t\treturn ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;\n\t\t}\n\t},\n\n\ttimers: [],\n\n\tfx: function( elem, options, prop ) {\n\t\tthis.options = options;\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\n\t\toptions.orig = options.orig || {};\n\t}\n\n});\n\njQuery.fx.prototype = {\n\t// Simple function for setting a style value\n\tupdate: function() {\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\t(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );\n\t},\n\n\t// Get the current size\n\tcur: function() {\n\t\tif ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {\n\t\t\treturn this.elem[ this.prop ];\n\t\t}\n\n\t\tvar parsed,\n\t\t\tr = jQuery.css( this.elem, this.prop );\n\t\t// Empty strings, null, undefined and \"auto\" are converted to 0,\n\t\t// complex values such as \"rotate(1rad)\" are returned as is,\n\t\t// simple values such as \"10px\" are parsed to Float.\n\t\treturn isNaN( parsed = parseFloat( r ) ) ? !r || r === \"auto\" ? 0 : r : parsed;\n\t},\n\n\t// Start an animation from one number to another\n\tcustom: function( from, to, unit ) {\n\t\tvar self = this,\n\t\t\tfx = jQuery.fx,\n\t\t\traf;\n\n\t\tthis.startTime = fxNow || createFxNow();\n\t\tthis.start = from;\n\t\tthis.end = to;\n\t\tthis.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? \"\" : \"px\" );\n\t\tthis.now = this.start;\n\t\tthis.pos = this.state = 0;\n\n\t\tfunction t( gotoEnd ) {\n\t\t\treturn self.step(gotoEnd);\n\t\t}\n\n\t\tt.elem = this.elem;\n\n\t\tif ( t() && jQuery.timers.push(t) && !timerId ) {\n\t\t\t// Use requestAnimationFrame instead of setInterval if available\n\t\t\tif ( requestAnimationFrame ) {\n\t\t\t\ttimerId = 1;\n\t\t\t\traf = function() {\n\t\t\t\t\t// When timerId gets set to null at any point, this stops\n\t\t\t\t\tif ( timerId ) {\n\t\t\t\t\t\trequestAnimationFrame( raf );\n\t\t\t\t\t\tfx.tick();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trequestAnimationFrame( raf );\n\t\t\t} else {\n\t\t\t\ttimerId = setInterval( fx.tick, fx.interval );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Simple 'show' function\n\tshow: function() {\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n\t\tthis.options.show = true;\n\n\t\t// Begin the animation\n\t\t// Make sure that we start at a small width/height to avoid any\n\t\t// flash of content\n\t\tthis.custom(this.prop === \"width\" || this.prop === \"height\" ? 1 : 0, this.cur());\n\n\t\t// Start by showing the element\n\t\tjQuery( this.elem ).show();\n\t},\n\n\t// Simple 'hide' function\n\thide: function() {\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n\t\tthis.options.hide = true;\n\n\t\t// Begin the animation\n\t\tthis.custom(this.cur(), 0);\n\t},\n\n\t// Each step of an animation\n\tstep: function( gotoEnd ) {\n\t\tvar t = fxNow || createFxNow(),\n\t\t\tdone = true,\n\t\t\telem = this.elem,\n\t\t\toptions = this.options,\n\t\t\ti, n;\n\n\t\tif ( gotoEnd || t >= options.duration + this.startTime ) {\n\t\t\tthis.now = this.end;\n\t\t\tthis.pos = this.state = 1;\n\t\t\tthis.update();\n\n\t\t\toptions.animatedProperties[ this.prop ] = true;\n\n\t\t\tfor ( i in options.animatedProperties ) {\n\t\t\t\tif ( options.animatedProperties[i] !== true ) {\n\t\t\t\t\tdone = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( done ) {\n\t\t\t\t// Reset the overflow\n\t\t\t\tif ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {\n\n\t\t\t\t\tjQuery.each( [ \"\", \"X\", \"Y\" ], function (index, value) {\n\t\t\t\t\t\telem.style[ \"overflow\" + value ] = options.overflow[index];\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Hide the element if the \"hide\" operation was done\n\t\t\t\tif ( options.hide ) {\n\t\t\t\t\tjQuery(elem).hide();\n\t\t\t\t}\n\n\t\t\t\t// Reset the properties, if the item has been hidden or shown\n\t\t\t\tif ( options.hide || options.show ) {\n\t\t\t\t\tfor ( var p in options.animatedProperties ) {\n\t\t\t\t\t\tjQuery.style( elem, p, options.orig[p] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Execute the complete function\n\t\t\t\toptions.complete.call( elem );\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t} else {\n\t\t\t// classical easing cannot be used with an Infinity duration\n\t\t\tif ( options.duration == Infinity ) {\n\t\t\t\tthis.now = t;\n\t\t\t} else {\n\t\t\t\tn = t - this.startTime;\n\t\t\t\tthis.state = n / options.duration;\n\n\t\t\t\t// Perform the easing function, defaults to swing\n\t\t\t\tthis.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );\n\t\t\t\tthis.now = this.start + ((this.end - this.start) * this.pos);\n\t\t\t}\n\t\t\t// Perform the next step of the animation\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn true;\n\t}\n};\n\njQuery.extend( jQuery.fx, {\n\ttick: function() {\n\t\tfor ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {\n\t\t\tif ( !timers[i]() ) {\n\t\t\t\ttimers.splice(i--, 1);\n\t\t\t}\n\t\t}\n\n\t\tif ( !timers.length ) {\n\t\t\tjQuery.fx.stop();\n\t\t}\n\t},\n\n\tinterval: 13,\n\n\tstop: function() {\n\t\tclearInterval( timerId );\n\t\ttimerId = null;\n\t},\n\n\tspeeds: {\n\t\tslow: 600,\n\t\tfast: 200,\n\t\t// Default speed\n\t\t_default: 400\n\t},\n\n\tstep: {\n\t\topacity: function( fx ) {\n\t\t\tjQuery.style( fx.elem, \"opacity\", fx.now );\n\t\t},\n\n\t\t_default: function( fx ) {\n\t\t\tif ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n\t\t\t\tfx.elem.style[ fx.prop ] = (fx.prop === \"width\" || fx.prop === \"height\" ? Math.max(0, fx.now) : fx.now) + fx.unit;\n\t\t\t} else {\n\t\t\t\tfx.elem[ fx.prop ] = fx.now;\n\t\t\t}\n\t\t}\n\t}\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\n\n// Try to restore the default display value of an element\nfunction defaultDisplay( nodeName ) {\n\n\tif ( !elemdisplay[ nodeName ] ) {\n\n\t\tvar elem = jQuery( \"<\" + nodeName + \">\" ).appendTo( \"body\" ),\n\t\t\tdisplay = elem.css( \"display\" );\n\n\t\telem.remove();\n\n\t\t// If the simple way fails,\n\t\t// get element's real default display by attaching it to a temp iframe\n\t\tif ( display === \"none\" || display === \"\" ) {\n\t\t\t// No iframe to use yet, so create it\n\t\t\tif ( !iframe ) {\n\t\t\t\tiframe = document.createElement( \"iframe\" );\n\t\t\t\tiframe.frameBorder = iframe.width = iframe.height = 0;\n\t\t\t}\n\n\t\t\tdocument.body.appendChild( iframe );\n\n\t\t\t// Create a cacheable copy of the iframe document on first call.\n\t\t\t// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake html\n\t\t\t// document to it, Webkit & Firefox won't allow reusing the iframe document\n\t\t\tif ( !iframeDoc || !iframe.createElement ) {\n\t\t\t\tiframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;\n\t\t\t\tiframeDoc.write( \"<!doctype><html><body></body></html>\" );\n\t\t\t}\n\n\t\t\telem = iframeDoc.createElement( nodeName );\n\n\t\t\tiframeDoc.body.appendChild( elem );\n\n\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t\tdocument.body.removeChild( iframe );\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn elemdisplay[ nodeName ];\n}\n\n\n\n\nvar rtable = /^t(?:able|d|h)$/i,\n\trroot = /^(?:body|html)$/i;\n\nif ( \"getBoundingClientRect\" in document.documentElement ) {\n\tjQuery.fn.offset = function( options ) {\n\t\tvar elem = this[0], box;\n\n\t\tif ( options ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t\t}\n\n\t\tif ( !elem || !elem.ownerDocument ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( elem === elem.ownerDocument.body ) {\n\t\t\treturn jQuery.offset.bodyOffset( elem );\n\t\t}\n\n\t\ttry {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t} catch(e) {}\n\n\t\tvar doc = elem.ownerDocument,\n\t\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure we're not dealing with a disconnected DOM node\n\t\tif ( !box || !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box ? { top: box.top, left: box.left } : { top: 0, left: 0 };\n\t\t}\n\n\t\tvar body = doc.body,\n\t\t\twin = getWindow(doc),\n\t\t\tclientTop  = docElem.clientTop  || body.clientTop  || 0,\n\t\t\tclientLeft = docElem.clientLeft || body.clientLeft || 0,\n\t\t\tscrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,\n\t\t\tscrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,\n\t\t\ttop  = box.top  + scrollTop  - clientTop,\n\t\t\tleft = box.left + scrollLeft - clientLeft;\n\n\t\treturn { top: top, left: left };\n\t};\n\n} else {\n\tjQuery.fn.offset = function( options ) {\n\t\tvar elem = this[0];\n\n\t\tif ( options ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t\t}\n\n\t\tif ( !elem || !elem.ownerDocument ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( elem === elem.ownerDocument.body ) {\n\t\t\treturn jQuery.offset.bodyOffset( elem );\n\t\t}\n\n\t\tjQuery.offset.initialize();\n\n\t\tvar computedStyle,\n\t\t\toffsetParent = elem.offsetParent,\n\t\t\tprevOffsetParent = elem,\n\t\t\tdoc = elem.ownerDocument,\n\t\t\tdocElem = doc.documentElement,\n\t\t\tbody = doc.body,\n\t\t\tdefaultView = doc.defaultView,\n\t\t\tprevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n\t\t\ttop = elem.offsetTop,\n\t\t\tleft = elem.offsetLeft;\n\n\t\twhile ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n\t\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcomputedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n\t\t\ttop  -= elem.scrollTop;\n\t\t\tleft -= elem.scrollLeft;\n\n\t\t\tif ( elem === offsetParent ) {\n\t\t\t\ttop  += elem.offsetTop;\n\t\t\t\tleft += elem.offsetLeft;\n\n\t\t\t\tif ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {\n\t\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t\t}\n\n\t\t\t\tprevOffsetParent = offsetParent;\n\t\t\t\toffsetParent = elem.offsetParent;\n\t\t\t}\n\n\t\t\tif ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== \"visible\" ) {\n\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t}\n\n\t\t\tprevComputedStyle = computedStyle;\n\t\t}\n\n\t\tif ( prevComputedStyle.position === \"relative\" || prevComputedStyle.position === \"static\" ) {\n\t\t\ttop  += body.offsetTop;\n\t\t\tleft += body.offsetLeft;\n\t\t}\n\n\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\ttop  += Math.max( docElem.scrollTop, body.scrollTop );\n\t\t\tleft += Math.max( docElem.scrollLeft, body.scrollLeft );\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t};\n}\n\njQuery.offset = {\n\tinitialize: function() {\n\t\tvar body = document.body, container = document.createElement(\"div\"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, \"marginTop\") ) || 0,\n\t\t\thtml = \"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";\n\n\t\tjQuery.extend( container.style, { position: \"absolute\", top: 0, left: 0, margin: 0, border: 0, width: \"1px\", height: \"1px\", visibility: \"hidden\" } );\n\n\t\tcontainer.innerHTML = html;\n\t\tbody.insertBefore( container, body.firstChild );\n\t\tinnerDiv = container.firstChild;\n\t\tcheckDiv = innerDiv.firstChild;\n\t\ttd = innerDiv.nextSibling.firstChild.firstChild;\n\n\t\tthis.doesNotAddBorder = (checkDiv.offsetTop !== 5);\n\t\tthis.doesAddBorderForTableAndCells = (td.offsetTop === 5);\n\n\t\tcheckDiv.style.position = \"fixed\";\n\t\tcheckDiv.style.top = \"20px\";\n\n\t\t// safari subtracts parent border width here which is 5px\n\t\tthis.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);\n\t\tcheckDiv.style.position = checkDiv.style.top = \"\";\n\n\t\tinnerDiv.style.overflow = \"hidden\";\n\t\tinnerDiv.style.position = \"relative\";\n\n\t\tthis.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);\n\n\t\tthis.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);\n\n\t\tbody.removeChild( container );\n\t\tjQuery.offset.initialize = jQuery.noop;\n\t},\n\n\tbodyOffset: function( body ) {\n\t\tvar top = body.offsetTop,\n\t\t\tleft = body.offsetLeft;\n\n\t\tjQuery.offset.initialize();\n\n\t\tif ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {\n\t\t\ttop  += parseFloat( jQuery.css(body, \"marginTop\") ) || 0;\n\t\t\tleft += parseFloat( jQuery.css(body, \"marginLeft\") ) || 0;\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t},\n\n\tsetOffset: function( elem, options, i ) {\n\t\tvar position = jQuery.css( elem, \"position\" );\n\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tvar curElem = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurCSSTop = jQuery.css( elem, \"top\" ),\n\t\t\tcurCSSLeft = jQuery.css( elem, \"left\" ),\n\t\t\tcalculatePosition = (position === \"absolute\" || position === \"fixed\") && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n\t\t\tprops = {}, curPosition = {}, curTop, curLeft;\n\n\t\t// need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif (options.top != null) {\n\t\t\tprops.top = (options.top - curOffset.top) + curTop;\n\t\t}\n\t\tif (options.left != null) {\n\t\t\tprops.left = (options.left - curOffset.left) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\n\tposition: function() {\n\t\tif ( !this[0] ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar elem = this[0],\n\n\t\t// Get *real* offsetParent\n\t\toffsetParent = this.offsetParent(),\n\n\t\t// Get correct offsets\n\t\toffset       = this.offset(),\n\t\tparentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n\n\t\t// Subtract element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\toffset.top  -= parseFloat( jQuery.css(elem, \"marginTop\") ) || 0;\n\t\toffset.left -= parseFloat( jQuery.css(elem, \"marginLeft\") ) || 0;\n\n\t\t// Add offsetParent borders\n\t\tparentOffset.top  += parseFloat( jQuery.css(offsetParent[0], \"borderTopWidth\") ) || 0;\n\t\tparentOffset.left += parseFloat( jQuery.css(offsetParent[0], \"borderLeftWidth\") ) || 0;\n\n\t\t// Subtract the two offsets\n\t\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top,\n\t\t\tleft: offset.left - parentOffset.left\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || document.body;\n\t\t\twhile ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, \"position\") === \"static\") ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( [\"Left\", \"Top\"], function( i, name ) {\n\tvar method = \"scroll\" + name;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\tvar elem, win;\n\n\t\tif ( val === undefined ) {\n\t\t\telem = this[ 0 ];\n\n\t\t\tif ( !elem ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\twin = getWindow( elem );\n\n\t\t\t// Return the scroll offset\n\t\t\treturn win ? (\"pageXOffset\" in win) ? win[ i ? \"pageYOffset\" : \"pageXOffset\" ] :\n\t\t\t\tjQuery.support.boxModel && win.document.documentElement[ method ] ||\n\t\t\t\t\twin.document.body[ method ] :\n\t\t\t\telem[ method ];\n\t\t}\n\n\t\t// Set the scroll offset\n\t\treturn this.each(function() {\n\t\t\twin = getWindow( this );\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!i ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\t i ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\tthis[ method ] = val;\n\t\t\t}\n\t\t});\n\t};\n});\n\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n\n\n\n\n// Create innerHeight, innerWidth, outerHeight and outerWidth methods\njQuery.each([ \"Height\", \"Width\" ], function( i, name ) {\n\n\tvar type = name.toLowerCase();\n\n\t// innerHeight and innerWidth\n\tjQuery.fn[\"inner\" + name] = function() {\n\t\treturn this[0] ?\n\t\t\tparseFloat( jQuery.css( this[0], type, \"padding\" ) ) :\n\t\t\tnull;\n\t};\n\n\t// outerHeight and outerWidth\n\tjQuery.fn[\"outer\" + name] = function( margin ) {\n\t\treturn this[0] ?\n\t\t\tparseFloat( jQuery.css( this[0], type, margin ? \"margin\" : \"border\" ) ) :\n\t\t\tnull;\n\t};\n\n\tjQuery.fn[ type ] = function( size ) {\n\t\t// Get window width or height\n\t\tvar elem = this[0];\n\t\tif ( !elem ) {\n\t\t\treturn size == null ? null : this;\n\t\t}\n\n\t\tif ( jQuery.isFunction( size ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tvar self = jQuery( this );\n\t\t\t\tself[ type ]( size.call( this, i, self[ type ]() ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode\n\t\t\t// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat\n\t\t\tvar docElemProp = elem.document.documentElement[ \"client\" + name ];\n\t\t\treturn elem.document.compatMode === \"CSS1Compat\" && docElemProp ||\n\t\t\t\telem.document.body[ \"client\" + name ] || docElemProp;\n\n\t\t// Get document width or height\n\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t// Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n\t\t\treturn Math.max(\n\t\t\t\telem.documentElement[\"client\" + name],\n\t\t\t\telem.body[\"scroll\" + name], elem.documentElement[\"scroll\" + name],\n\t\t\t\telem.body[\"offset\" + name], elem.documentElement[\"offset\" + name]\n\t\t\t);\n\n\t\t// Get or set width or height on the element\n\t\t} else if ( size === undefined ) {\n\t\t\tvar orig = jQuery.css( elem, type ),\n\t\t\t\tret = parseFloat( orig );\n\n\t\t\treturn jQuery.isNaN( ret ) ? orig : ret;\n\n\t\t// Set the width or height on the element (default to pixels if value is unitless)\n\t\t} else {\n\t\t\treturn this.css( type, typeof size === \"string\" ? size : size + \"px\" );\n\t\t}\n\t};\n\n});\n\n\nwindow.jQuery = window.$ = jQuery;\n})(window);\n"
  },
  {
    "path": "springWebSocket/src/main/resources/templates/chat.html",
    "content": "<!DOCTYPE html>\r\n\r\n<html xmlns:th=\"http://www.thymeleaf.org\">\r\n<meta charset=\"UTF-8\" />\r\n<head>\r\n    <title>Home</title>\r\n    <script th:src=\"@{sockjs.min.js}\"></script>\r\n    <script th:src=\"@{stomp.min.js}\"></script>\r\n    <script th:src=\"@{jquery.js}\"></script>\r\n</head>\r\n<body>\r\n<p>\r\n    聊天室\r\n</p>\r\n\r\n<form id=\"wiselyForm\">\r\n    <textarea rows=\"4\" cols=\"60\" name=\"text\"></textarea>\r\n    <input type=\"submit\"/>\r\n</form>\r\n\r\n<script th:inline=\"javascript\">\r\n    $('#wiselyForm').submit(function(e){\r\n        e.preventDefault();\r\n        var text = $('#wiselyForm').find('textarea[name=\"text\"]').val();\r\n        sendSpittle(text);\r\n    });\r\n    //链接endpoint名称为 \"/endpointChat\" 的endpoint。\r\n    var sock = new SockJS(\"/endpointChat\");\r\n    var stomp = Stomp.over(sock);\r\n    stomp.connect('guest', 'guest', function(frame) {\r\n\r\n        /**  订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致, \r\n         *  这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。 \r\n         *  */\r\n        stomp.subscribe(\"/user/queue/notifications\", handleNotification);\r\n    });\r\n\r\n\r\n\r\n    function handleNotification(message) {\r\n        $('#output').append(\"<b>Received: \" + message.body + \"</b><br/>\")\r\n    }\r\n\r\n    function sendSpittle(text) {\r\n        stomp.send(\"/chat\", {}, JSON.stringify({ 'name': text }));//3\r\n    }\r\n    $('#stop').click(function() {sock.close()});\r\n</script>\r\n\r\n<div id=\"output\"></div>\r\n</body>\r\n</html>"
  },
  {
    "path": "springWebSocket/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\"\r\n      xmlns:sec=\"http://www.thymeleaf.org/thymeleaf-extras-springsecurity3\">\r\n<meta charset=\"UTF-8\" />\r\n<head>\r\n    <title>登陆页面</title>\r\n</head>\r\n<body>\r\n<div th:if=\"${param.error}\">\r\n    无效的账号和密码\r\n</div>\r\n<div th:if=\"${param.logout}\">\r\n    你已注销\r\n</div>\r\n<form th:action=\"@{/login}\" method=\"post\">\r\n    <div><label> 账号 : <input type=\"text\" name=\"username\"/> </label></div>\r\n    <div><label> 密码: <input type=\"password\" name=\"password\"/> </label></div>\r\n    <div><input type=\"submit\" value=\"登陆\"/></div>\r\n</form>\r\n</body>\r\n</html>"
  },
  {
    "path": "springWebSocket/src/main/resources/templates/ws.html",
    "content": "<!DOCTYPE html>\r\n<html xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"UTF-8\" />\r\n    <title>Spring Boot+WebSocket+广播式</title>\r\n\r\n</head>\r\n<body onload=\"disconnect()\">\r\n<noscript><h2 style=\"color: #ff0000\">貌似你的浏览器不支持websocket</h2></noscript>\r\n<div>\r\n    <div>\r\n        <button id=\"connect\" onclick=\"connect();\">连接</button>\r\n        <button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">断开连接</button>\r\n    </div>\r\n    <div id=\"conversationDiv\">\r\n        <label>输入你的名字</label><input type=\"text\" id=\"name\" />\r\n        <button id=\"sendName\" onclick=\"sendName();\">发送</button>\r\n        <p id=\"response\"></p>\r\n    </div>\r\n</div>\r\n<script th:src=\"@{sockjs.min.js}\"></script>\r\n<script th:src=\"@{stomp.min.js}\"></script>\r\n<script th:src=\"@{jquery.js}\"></script>\r\n<script type=\"text/javascript\">\r\n    var stompClient = null;\r\n\r\n    function setConnected(connected) {\r\n        document.getElementById('connect').disabled = connected;\r\n        document.getElementById('disconnect').disabled = !connected;\r\n        document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';\r\n        $('#response').html();\r\n    }\r\n\t\r\n    function connect() {\r\n        var socket = new SockJS('/endpointWisely'); //链接SockJS 的endpoint 名称为\"/endpointWisely\"\r\n        stompClient = Stomp.over(socket);//使用stomp子协议的WebSocket 客户端\r\n        stompClient.connect({}, function(frame) {//链接Web Socket的服务端。\r\n            setConnected(true);\r\n            console.log('Connected: ' + frame);\r\n            stompClient.subscribe('/topic/getResponse', function(respnose){ //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。\r\n                showResponse(JSON.parse(respnose.body).responseMessage);\r\n            });\r\n        });\r\n    }\r\n\t\r\n\t\r\n    function disconnect() {\r\n        if (stompClient != null) {\r\n            stompClient.disconnect();\r\n        }\r\n        setConnected(false);\r\n        console.log(\"Disconnected\");\r\n    }\r\n\r\n    function sendName() {\r\n        var name = $('#name').val();\r\n   \t\t//通过stompClient.send 向/welcome 目标 发送消息,这个是在控制器的@messageMapping 中定义的。\r\n        stompClient.send(\"/welcome\", {}, JSON.stringify({ 'name': name }));\r\n    }\r\n\r\n    function showResponse(message) {\r\n          var response = $(\"#response\");\r\n          response.html(message);\r\n    }\r\n</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "springboot-Cache/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-Cache</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n    <!-- Add typical dependencies for a web application -->\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-cache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!--切换缓存 ehcache-->\n        <!--<dependency>-->\n            <!--<groupId>net.sf.ehcache</groupId>-->\n            <!--<artifactId>ehcache</artifactId>-->\n        <!--</dependency>-->\n\n        <!--切换缓存 guava-->\n        <!--<dependency>-->\n            <!--<groupId>com.google.guava</groupId>-->\n            <!--<artifactId>guava</artifactId>-->\n            <!--<version>18.0</version>-->\n        <!--</dependency>-->\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-redis</artifactId>\n        </dependency>\n\n        <!--db-->\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.*;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/bean/Person.java",
    "content": "package com.us.example.bean;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport java.io.Serializable;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@Entity\n@Table(name = \"Person\")\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = 133938246231808718L;\n\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String name;\n\n    private Integer age;\n\n    private String address;\n\n    public Person() {\n        super();\n    }\n    public Person(Long id, String name, Integer age, String address) {\n        super();\n        this.id = id;\n        this.name = name;\n        this.age = age;\n        this.address = address;\n    }\n    public Long getId() {\n        return id;\n    }\n    public void setId(Long id) {\n        this.id = id;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n    public Integer getAge() {\n        return age;\n    }\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n    public String getAddress() {\n        return address;\n    }\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n\n}\n\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/config/DBConfig.java",
    "content": "package com.us.example.config;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/config/JpaConfig.java",
    "content": "package com.us.example.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n\n@Configuration\n@EnableJpaRepositories(\"com.us.example.dao\")\n@EnableTransactionManagement\n@ComponentScan\npublic class JpaConfig {\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean\n    public EntityManagerFactory entityManagerFactory() {\n        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();\n        //vendorAdapter.setShowSql(true);\n        //vendorAdapter.setGenerateDdl(true);\n\n        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();\n        factory.setJpaVendorAdapter(vendorAdapter);\n        factory.setPackagesToScan(\"com.us.example.bean\");\n        factory.setDataSource(dataSource);\n\n\n        Map<String, Object> jpaProperties = new HashMap<>();\n        jpaProperties.put(\"hibernate.ejb.naming_strategy\",\"org.hibernate.cfg.ImprovedNamingStrategy\");\n        jpaProperties.put(\"hibernate.jdbc.batch_size\",50);\n        //jpaProperties.put(\"hibernate.show_sql\",true);\n\n        factory.setJpaPropertyMap(jpaProperties);\n        factory.afterPropertiesSet();\n        return factory.getObject();\n    }\n\n    @Bean\n    public PlatformTransactionManager transactionManager() {\n\n        JpaTransactionManager txManager = new JpaTransactionManager();\n        txManager.setEntityManagerFactory(entityManagerFactory());\n        return txManager;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/config/RedisConfig.java",
    "content": "package com.us.example.config;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.CachingConfigurerSupport;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.interceptor.CacheErrorHandler;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\n/**\n * Created by yangyibo on 17/1/16.\n */\n@Configuration\n@EnableCaching\npublic class RedisConfig extends CachingConfigurerSupport{\n    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);\n\n    @Autowired\n    private Environment env;\n\n    @Bean\n    public JedisConnectionFactory redisConnectionFactory() {\n        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();\n        redisConnectionFactory.setHostName(env.getProperty(\"redis.hostname\"));\n        redisConnectionFactory.setPort(Integer.parseInt(env.getProperty(\"redis.port\")));\n        return redisConnectionFactory;\n    }\n\n    @Bean\n    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {\n        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();\n        redisTemplate.setConnectionFactory(cf);\n        return redisTemplate;\n    }\n\n    @Bean\n    public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {\n        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);\n        cacheManager.setDefaultExpiration(600);\n        return cacheManager;\n    }\n\n    public CacheErrorHandler errorHandler() {\n        return new CacheErrorHandler(){\n\n            @Override\n            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {\n                logger.warn(\"handleCacheGetError in redis: {}\", exception.getMessage());\n            }\n\n            @Override\n            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {\n                logger.warn(\"handleCachePutError in redis: {}\", exception.getMessage());\n            }\n\n            @Override\n            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {\n                logger.warn(\"handleCacheEvictError in redis: {}\", exception.getMessage());\n            }\n\n            @Override\n            public void handleCacheClearError(RuntimeException exception, Cache cache) {\n                logger.warn(\"handleCacheClearError in redis: {}\", exception.getMessage());\n            }};\n    }\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/controller/CacheController.java",
    "content": "package com.us.example.controller;\nimport com.us.example.bean.Person;\nimport com.us.example.service.DemoService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@RestController\npublic class CacheController {\n\n    @Autowired\n   private DemoService demoService;\n\n    //http://localhost:8080/put?name=abel&age=23&address=shanghai\n    @RequestMapping(\"/put\")\n    public Person put(Person person){\n        return demoService.save(person);\n\n    }\n\n    //http://localhost:8080/able?id=1\n    @RequestMapping(\"/able\")\n    @ResponseBody\n    public Person cacheable(Person person){\n\n\n        return demoService.findOne(person);\n\n    }\n\n    //http://localhost:8080/evit?id=1\n    @RequestMapping(\"/evit\")\n    public String  evit(Long id){\n        demoService.remove(id);\n        return \"ok\";\n\n    }\n\n\n}"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/dao/PersonRepository.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.bean.Person;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\npublic interface PersonRepository extends JpaRepository<Person, Long> {\n\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/service/DemoService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.bean.Person;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\npublic  interface DemoService {\n    public Person save(Person person);\n\n    public void remove(Long id);\n\n    public Person findOne(Person person);\n\n}\n"
  },
  {
    "path": "springboot-Cache/src/main/java/com/us/example/service/Impl/DemoServiceImpl.java",
    "content": "package com.us.example.service.Impl;\n\nimport com.us.example.bean.Person;\nimport com.us.example.dao.PersonRepository;\nimport com.us.example.service.DemoService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.annotation.CacheEvict;\nimport org.springframework.cache.annotation.CachePut;\nimport org.springframework.cache.annotation.Cacheable;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@Service\npublic class DemoServiceImpl implements DemoService {\n\n    @Autowired\n    private PersonRepository personRepository;\n\n    @Override\n    //@CachePut缓存新增的或更新的数据到缓存,其中缓存名字是 people 。数据的key是person的id\n    @CachePut(value = \"people\", key = \"#person.id\")\n    public Person save(Person person) {\n        Person p = personRepository.save(person);\n        System.out.println(\"为id、key为:\"+p.getId()+\"数据做了缓存\");\n        return p;\n    }\n\n    @Override\n    //@CacheEvict 从缓存people中删除key为id 的数据\n    @CacheEvict(value = \"people\")\n    public void remove(Long id) {\n        System.out.println(\"删除了id、key为\"+id+\"的数据缓存\");\n        //这里不做实际删除操作\n    }\n\n    @Override\n    //@Cacheable缓存key为person 的id 数据到缓存people 中,如果没有指定key则方法参数作为key保存到缓存中。\n    @Cacheable(value = \"people\", key = \"#person.id\")\n    public Person findOne(Person person) {\n        Person p = personRepository.findOne(person.getId());\n        System.out.println(\"为id、key为:\"+p.getId()+\"数据做了缓存\");\n        return p;\n    }\n\n}"
  },
  {
    "path": "springboot-Cache/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\n#最多缓存 500 条 ，缓存在 30 分钟后失效\r\n#spring.cache.guava.spec= maximumSize=500,expireAfterWrite=30m\r\n#redis.hostname=xxxxxx\r\n\r\nredis.hostname=xxxxxx\r\nredis.port=6379"
  },
  {
    "path": "springboot-Cache/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<ehcache>\r\n    <!--切换为ehcache 缓存时使用-->\r\n<cache name=\"people\" maxElementsInMemory=\"1000\" />\r\n</ehcache>"
  },
  {
    "path": "springboot-Cache2/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-Cache2</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n    <!-- Add typical dependencies for a web application -->\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-cache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!--缓存-->\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <version>18.0</version>\n        </dependency>\n\n        <!--db-->\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.*;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/bean/Person.java",
    "content": "package com.us.example.bean;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport java.io.Serializable;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@Entity\n@Table(name = \"Person\")\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = 133938246231808718L;\n\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String name;\n\n    private Integer age;\n\n    private String address;\n\n    public Person() {\n        super();\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public Person(Long id, String name, Integer age, String address) {\n        super();\n        this.id = id;\n        this.name = name;\n        this.age = age;\n        this.address = address;\n    }\n\n    @Override\n    public String toString() {\n        return \"Person{\" +\n                \"id=\" + id +\n                \", name=\" + name +\n                \", age=\" + age +\n                \", address=\" + address +\n                '}';\n    }\n\n}\n\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/config/CacheConfig.java",
    "content": "package com.us.example.config;\n\nimport com.us.example.bean.Person;\nimport com.us.example.service.DemoService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.guava.GuavaCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/3/2.\n */\n@Configuration\npublic class CacheConfig {\n\n    @Autowired\n    private DemoService demoService;\n\n    @Bean\n    public CacheManager getCacheManager() {\n        List<Person> personList = demoService.findAll();\n        //所有缓存的名字\n        List<String> cacheNames = new ArrayList();\n        GuavaCacheManager cacheManager = new GuavaCacheManager();\n        //GuavaCacheManager 的数据结构类似  Map<String,Map<Object,Object>>  map =new HashMap<>();\n\n        //将数据放入缓存\n        personList.stream().forEach(person -> {\n            //用person 的id cacheName\n            String cacheName=person.getId().toString();\n            if(cacheManager.getCache(cacheName)==null){\n                //为每一个person 如果不存在，创建一个新的缓存对象\n                cacheNames.add(cacheName);\n                cacheManager.setCacheNames(cacheNames);\n            }\n            Cache cache = cacheManager.getCache(cacheName);\n            //缓存对象用person的id当作缓存的key 用person 当作缓存的value\n            cache.put(person.getId(),person);\n            System.out.println(\"为 ID 为\"+cacheName+ \"的person 数据做了缓存\");\n        });\n        return cacheManager;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/config/DBConfig.java",
    "content": "package com.us.example.config;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/config/JpaConfig.java",
    "content": "package com.us.example.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n\n@Configuration\n@EnableJpaRepositories(\"com.us.example.dao\")\n@EnableTransactionManagement\n@ComponentScan\npublic class JpaConfig {\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean\n    public EntityManagerFactory entityManagerFactory() {\n        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();\n        //vendorAdapter.setShowSql(true);\n        //vendorAdapter.setGenerateDdl(true);\n\n        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();\n        factory.setJpaVendorAdapter(vendorAdapter);\n        factory.setPackagesToScan(\"com.us.example.bean\");\n        factory.setDataSource(dataSource);\n\n\n        Map<String, Object> jpaProperties = new HashMap<>();\n        jpaProperties.put(\"hibernate.ejb.naming_strategy\",\"org.hibernate.cfg.ImprovedNamingStrategy\");\n        jpaProperties.put(\"hibernate.jdbc.batch_size\",50);\n        //jpaProperties.put(\"hibernate.show_sql\",true);\n\n        factory.setJpaPropertyMap(jpaProperties);\n        factory.afterPropertiesSet();\n        return factory.getObject();\n    }\n\n    @Bean\n    public PlatformTransactionManager transactionManager() {\n\n        JpaTransactionManager txManager = new JpaTransactionManager();\n        txManager.setEntityManagerFactory(entityManagerFactory());\n        return txManager;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/controller/CacheController.java",
    "content": "package com.us.example.controller;\nimport com.us.example.bean.Person;\nimport com.us.example.service.PersonService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@RestController\n@RequestMapping(value = \"/person\")\npublic class CacheController {\n\n    @Autowired\n   private PersonService personService;\n\n\n    @RequestMapping(method = RequestMethod.POST)\n    @ResponseBody\n    public Person put(Person person){\n        return personService.save(person);\n\n    }\n\n    //http://localhost:8080/person/1\n    @RequestMapping(value =\"/{id}\" ,method = RequestMethod.GET)\n    @ResponseBody\n    public Person cacheable( @PathVariable Long id){\n        return personService.findOne(id);\n\n    }\n\n}"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/dao/PersonRepository.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.bean.Person;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\npublic interface PersonRepository extends JpaRepository<Person, Long> {\n\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/service/DemoService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.bean.Person;\nimport com.us.example.dao.PersonRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/13.\n */\n@Service\npublic class DemoService {\n\n    @Autowired\n    private PersonRepository personRepository;\n\n\n    public List<Person> findAll() {\n        return personRepository.findAll();\n    }\n\n}"
  },
  {
    "path": "springboot-Cache2/src/main/java/com/us/example/service/PersonService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.bean.Person;\nimport com.us.example.dao.PersonRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created by yangyibo on 17/3/2.\n */\n@Service\npublic class PersonService {\n    @Autowired\n    CacheManager cacheManager;\n\n    @Autowired\n    private PersonRepository personRepository;\n\n\n    public Person findOne(Long id) {\n        Person person = getCache(id, cacheManager);\n        if (person != null) {\n            System.out.println(\"从缓存中取出:\" + person.toString());\n        } else {\n            person = personRepository.findOne(id);\n            System.out.println(\"从数据库中取出:\" + person.toString());\n\n        }\n        return person;\n    }\n\n    public Person save(Person person) {\n        Person p = personRepository.save(person);\n        return p;\n    }\n\n\n    public Person getCache(Long id, CacheManager cacheManager) {\n\n//   Person person=(Person) cacheManager.getCache(id.toString()).get(id).get();\n\n        Cache cache = cacheManager.getCache(id.toString());\n        Cache.ValueWrapper valueWrapper = cache.get(id);\n        Person person = (Person) valueWrapper.get();\n        return person;\n    }\n}\n"
  },
  {
    "path": "springboot-Cache2/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\n"
  },
  {
    "path": "springboot-Quartz/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.abel.quartz</groupId>\n    <artifactId>springboot-Quartz</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!--quartz-->\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n            <version>2.2.1</version>\n        </dependency>\n        <!--因为quartz 需要有Spring context 所有引入mail包-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-mail</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>3.2.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.18.1</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-Quartz/src/main/java/com/abel/quartz/Application.java",
    "content": "package com.abel.quartz;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ImportResource;\n\n/**\n * Created by yangyibo on 2019/2/1.\n */\n@SpringBootApplication\n@ImportResource(\"classpath*:META-INF/spring/*.xml\")\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n\n}\n"
  },
  {
    "path": "springboot-Quartz/src/main/java/com/abel/quartz/config/InvokingJobDetailFactory.java",
    "content": "package com.abel.quartz.config;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.scheduling.quartz.QuartzJobBean;\nimport java.lang.reflect.Method;\n\n\n/**\n * Created by yangyibo on 2019/2/1.\n */\npublic class InvokingJobDetailFactory extends QuartzJobBean {\n\n    /**\n     * 计划任务所在类\n     */\n    private String targetObject;\n\n    /**\n     * 具体需要执行的计划任务\n     */\n    private String targetMethod;\n\n    private ApplicationContext ctx;\n\n    @Override\n    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {\n        try {\n            Object obj = ctx.getBean(targetObject);\n            Method m = null;\n            try {\n                m = obj.getClass().getMethod(targetMethod);\n                //调用被代理对象的方法\n                m.invoke(obj);\n            } catch (SecurityException e) {\n                e.printStackTrace();\n            } catch (NoSuchMethodException e) {\n                e.printStackTrace();\n            }\n        } catch (Exception e) {\n            throw new JobExecutionException(e);\n        }\n    }\n\n    public void setApplicationContext(ApplicationContext applicationContext) {\n        this.ctx = applicationContext;\n    }\n\n    public void setTargetObject(String targetObject) {\n        this.targetObject = targetObject;\n    }\n\n    public void setTargetMethod(String targetMethod) {\n        this.targetMethod = targetMethod;\n    }\n}\n"
  },
  {
    "path": "springboot-Quartz/src/main/java/com/abel/quartz/config/QuartzConfig.java",
    "content": "package com.abel.quartz.config;\n\nimport java.beans.PropertyVetoException;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.Trigger;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.quartz.CronTriggerFactoryBean;\nimport org.springframework.scheduling.quartz.JobDetailFactoryBean;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\n\n/**\n * Created by yangyibo on 2019/1/16.\n */\n@Configuration\npublic class QuartzConfig {\n\n    /**\n     * 1.通过name+group获取唯一的jobKey;2.通过groupname来获取其下的所有jobkey\n     */\n    final static String GROUP_NAME = \"QuartzJobGroups\";\n\n    @Value(\"${quartz.scheduler.instanceName}\")\n    private String quartzInstanceName;\n\n    @Value(\"${spring.datasource.driverClassName}\")\n    private String myDSDriver;\n\n    @Value(\"${spring.datasource.url}\")\n    private String myDSUrl;\n\n    @Value(\"${spring.datasource.username}\")\n    private String myDSUser;\n\n    @Value(\"${spring.datasource.password}\")\n    private String myDSPassword;\n\n    @Value(\"${org.quartz.dataSource.myDS.maxConnections}\")\n    private int myDSMaxConnections;\n\n    /**\n     * 设置属性\n     *\n     * @return\n     * @throws IOException\n     */\n    private Properties quartzProperties() throws IOException {\n        Properties prop = new Properties();\n        // 调度标识名 集群中每一个实例都必须使用相同的名称\n        prop.put(\"quartz.scheduler.instanceName\", quartzInstanceName);\n        // ID设置为自动获取 每一个必须不同\n        prop.put(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        // 禁用quartz软件更新\n        prop.put(\"org.quartz.scheduler.skipUpdateCheck\", \"true\");\n        prop.put(\"org.quartz.scheduler.jmx.export\", \"true\");\n\n\n        // 数据库代理类，一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库\n        prop.put(\"org.quartz.jobStore.driverDelegateClass\", \"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\n        // 数据保存方式为数据库持久化\n        prop.put(\"org.quartz.jobStore.class\", \"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n        // 数据库别名 随便取\n        prop.put(\"org.quartz.jobStore.dataSource\", \"quartzDataSource\");\n        //prop.put(\"org.quartz.jobStore.dataSource\", \"myDS\");\n        // 表的前缀，默认QRTZ_\n        prop.put(\"org.quartz.jobStore.tablePrefix\", \"QRTZ_\");\n        // 是否加入集群\n        prop.put(\"org.quartz.jobStore.isClustered\", \"true\");\n\n        // 调度实例失效的检查时间间隔\n        prop.put(\"org.quartz.jobStore.clusterCheckinInterval\", \"20000\");\n        prop.put(\"org.quartz.jobStore.maxMisfiresToHandleAtATime\", \"1\");\n        // 信息保存时间 ms 默认值60秒\n        prop.put(\"org.quartz.jobStore.misfireThreshold\", \"120000\");\n        prop.put(\"org.quartz.jobStore.txIsolationLevelSerializable\", \"true\");\n        prop.put(\"org.quartz.jobStore.selectWithLockSQL\", \"SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE\");\n\n        // 程池的实现类（一般使用SimpleThreadPool即可满足几乎所有用户的需求）\n        prop.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        // 定线程数，至少为1（无默认值）(一般设置为1-100之间的整数合适)\n        prop.put(\"org.quartz.threadPool.threadCount\", \"10\");\n        // 设置线程的优先级（最大为java.lang.Thread.MAX_PRIORITY 10，最小为Thread.MIN_PRIORITY 1，默认为5）\n        prop.put(\"org.quartz.threadPool.threadPriority\", \"5\");\n        prop.put(\"org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread\", \"true\");\n\n        prop.put(\"org.quartz.plugin.triggHistory.class\", \"org.quartz.plugins.history.LoggingJobHistoryPlugin\");\n        prop.put(\"org.quartz.plugin.shutdownhook.class\", \"org.quartz.plugins.management.ShutdownHookPlugin\");\n        prop.put(\"org.quartz.plugin.shutdownhook.cleanShutdown\", \"true\");\n\n        //#自定义连接池\n        //org.quartz.dataSource.myDS.connectionProvider.class=com.poly.pay.schedule.DruidConnectionProvider\n\n        return prop;\n    }\n\n    /**\n     * 数据源\n     *\n     * @return\n     * @throws PropertyVetoException\n     */\n    @Bean\n    public HikariDataSource createDataSource() throws PropertyVetoException {\n        HikariDataSource dataSource = new HikariDataSource();\n        dataSource.setJdbcUrl(myDSUrl);\n        dataSource.setDriverClassName(myDSDriver);\n        dataSource.setUsername(myDSUser);\n        dataSource.setPassword(myDSPassword);\n        dataSource.setMaximumPoolSize(myDSMaxConnections);\n        return dataSource;\n    }\n\n\n    /**\n     * 创建触发器工厂\n     *\n     * @param jobDetail\n     * @param cronExpression\n     * @return\n     */\n    private static CronTriggerFactoryBean cronTriggerFactoryBean(JobDetail jobDetail, String cronExpression) {\n        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();\n        factoryBean.setJobDetail(jobDetail);\n        factoryBean.setCronExpression(cronExpression);\n        return factoryBean;\n    }\n\n\n/****************************************************以下配置需要注意******************************************************/\n\n\n    /**\n     * 调度工厂\n     * 此处配置需要调度的触发器 例如 executeJobTrigger\n     *\n     * @param executeJobTrigger\n     * @return\n     * @throws IOException\n     * @throws PropertyVetoException\n     */\n    @Bean\n    public SchedulerFactoryBean schedulerFactoryBean(@Qualifier(\"executeJobTrigger\") Trigger executeJobTrigger) throws IOException, PropertyVetoException {\n        SchedulerFactoryBean factory = new SchedulerFactoryBean();\n        // this allows to update triggers in DB when updating settings in config file:\n        //用于quartz集群,QuartzScheduler 启动时更新己存在的Job，这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了\n        factory.setOverwriteExistingJobs(true);\n        //用于quartz集群,加载quartz数据源\n        //factory.setDataSource(dataSource);\n        //QuartzScheduler 延时启动，应用启动完10秒后 QuartzScheduler 再启动\n        //factory.setStartupDelay(10);\n        //用于quartz集群,加载quartz数据源配置\n        factory.setAutoStartup(true);\n        factory.setQuartzProperties(quartzProperties());\n        factory.setApplicationContextSchedulerContextKey(\"applicationContext\");\n        factory.setDataSource(createDataSource());\n        //注册触发器\n        Trigger[] triggers = {executeJobTrigger};\n        factory.setTriggers(triggers);\n\n        return factory;\n    }\n\n\n    /**\n     * 加载触发器\n     *\n     * 新建触发器进行job 的调度  例如 executeJobDetail\n     * @param jobDetail\n     * @return\n     */\n    @Bean(name = \"executeJobTrigger\")\n    public CronTriggerFactoryBean executeJobTrigger(@Qualifier(\"executeJobDetail\") JobDetail jobDetail) {\n        //每天凌晨3点执行\n        return cronTriggerFactoryBean(jobDetail, \"0 1 0 * * ? \");\n    }\n\n\n    /**\n     * 加载job\n     *\n     * 新建job 类用来代理\n     *\n     *\n     * @return\n     */\n    @Bean\n    public JobDetailFactoryBean executeJobDetail() {\n        return createJobDetail(InvokingJobDetailFactory.class, GROUP_NAME, \"executeJob\");\n    }\n\n\n    /**\n     * 执行规则job工厂\n     *\n     * 配置job 类中需要定时执行的 方法  execute\n     * @param jobClass\n     * @param groupName\n     * @param targetObject\n     * @return\n     */\n    private static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass,\n                                                        String groupName,\n                                                        String targetObject) {\n        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();\n        factoryBean.setJobClass(jobClass);\n        factoryBean.setDurability(true);\n        factoryBean.setRequestsRecovery(true);\n        factoryBean.setGroup(groupName);\n        Map<String, String> map = new HashMap<>();\n        map.put(\"targetMethod\", \"execute\");\n        map.put(\"targetObject\", targetObject);\n        factoryBean.setJobDataAsMap(map);\n        return factoryBean;\n    }\n\n}"
  },
  {
    "path": "springboot-Quartz/src/main/java/com/abel/quartz/job/ExecuteJob.java",
    "content": "package com.abel.quartz.job;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created by yangyibo on 2019/2/1.\n */\n@Service\npublic class ExecuteJob {\n    private static final Logger logger = LoggerFactory.getLogger(ExecuteJob.class);\n\n    /**\n     * 方法名在quartz定义\n     */\n    public void execute() {\n        System.out.println(\"定时任务执行了。。。。。\");\n\n    }\n}\n"
  },
  {
    "path": "springboot-Quartz/src/main/resources/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=8090\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.abel.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200  \nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-Quartz\napplication.main=com.abel.quartz.Application\n\n\n## \\u4E3B\\u6570\\u636E\\u6E90\\uFF0C\\u9ED8\\u8BA4\\u7684\nspring.datasource.url=jdbc:mysql://localhost:3306/quartz?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\n## \\u8FDE\\u63A5\\u6C60\\u914D\\u7F6E\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\n#\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.datasource.hikari.minimum-idle=10\n#\\u8FDE\\u63A5\\u6C60\\u4E2D\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\u3002\\u7F3A\\u7701\\u503C\\uFF1A10\\uFF1B\\u63A8\\u8350\\u7684\\u516C\\u5F0F\\uFF1A((core_count * 2) + effective_spindle_count)\nspring.datasource.hikari.maximum-pool-size=30\n#spring.datasource.hikari.auto-commit=true\n#\\u4E00\\u4E2A\\u8FDE\\u63A5idle\\u72B6\\u6001\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\\uFF0C\\u8D85\\u65F6\\u5219\\u88AB\\u91CA\\u653E\\uFF08retired\\uFF09\\uFF0C\\u7F3A\\u7701:10\\u5206\\u949F\\u3002minimumIdle<maximumPoolSize\\u65F6\\u751F\\u6548\nspring.datasource.hikari.idle-timeout=120000\n#\\u81EA\\u5B9A\\u4E49\\u8FDE\\u63A5\\u6C60\\u540D\n#spring.datasource.hikari.pool-name=DatebookHikariCP\n#\\u4E00\\u4E2A\\u8FDE\\u63A5\\u7684\\u751F\\u547D\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\\uFF0C\\u8D85\\u65F6\\u800C\\u4E14\\u6CA1\\u88AB\\u4F7F\\u7528\\u5219\\u88AB\\u91CA\\u653E\\uFF08retired\\uFF09\\uFF0C\\u7F3A\\u7701:30\\u5206\\u949F\\uFF0C\\u5EFA\\u8BAE\\u8BBE\\u7F6E\\u6BD4\\u6570\\u636E\\u5E93\\u8D85\\u65F6\\u65F6\\u957F\\u5C1130\\u79D2\\uFF0C\\u53C2\\u8003MySQL wait_timeout\\u53C2\\u6570\\uFF08show variables like '%timeout%';\\uFF09\nspring.datasource.hikari.max-lifetime=1800000\n#\\u7B49\\u5F85\\u8FDE\\u63A5\\u6C60\\u5206\\u914D\\u8FDE\\u63A5\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\\uFF0C\\u8D85\\u8FC7\\u8FD9\\u4E2A\\u65F6\\u957F\\u8FD8\\u6CA1\\u53EF\\u7528\\u7684\\u8FDE\\u63A5\\u5219\\u53D1\\u751FSQLException\\uFF0C \\u7F3A\\u7701:30\\u79D2\nspring.datasource.hikari.connection-timeout=30000\n#\\u6307\\u5B9A\\u9A8C\\u8BC1\\u8FDE\\u63A5\\u6709\\u6548\\u6027\\u7684\\u8D85\\u65F6\\u65F6\\u95F4\\uFF0C\\u9ED8\\u8BA4\\u662F5\\u79D2\nspring.datasource.hikari.validation-timeout=3000\nspring.datasource.hikari.connection-test-query=SELECT 1\n\n# \\u8C03\\u5EA6\\u6807\\u8BC6\\u540D \\u96C6\\u7FA4\\u4E2D\\u6BCF\\u4E00\\u4E2A\\u5B9E\\u4F8B\\u90FD\\u5FC5\\u987B\\u4F7F\\u7528\\u76F8\\u540C\\u7684\\u540D\\u79F0\nquartz.scheduler.instanceName=QuartScheduler\n# \\u5141\\u8BB8\\u6700\\u5927\\u8FDE\\u63A5\norg.quartz.dataSource.myDS.maxConnections=10\n"
  },
  {
    "path": "springboot-Quartz/src/main/resources/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-Quartz/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-quartz</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-SpringSecurity0/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-security0</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!-- 用于home.html文件中的 hasRole('ROLE_ADMIN') 语句-->\n        <dependency>\n            <groupId>org.thymeleaf.extras</groupId>\n            <artifactId>thymeleaf-extras-springsecurity4</artifactId>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/DBconfig.java",
    "content": "package com.us.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\npublic class DBconfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/MyBatisConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class MyBatisConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"sqlSessionFactory\")\n    public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {\n        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        // sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n        sessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n        return sessionFactory;\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/MyBatisScannerConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/TransactionConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/WebMvcConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\n\npublic class WebMvcConfig extends WebMvcConfigurerAdapter{\n\n    @Override\n    public void addViewControllers(ViewControllerRegistry registry) {\n        registry.addViewController(\"/login\").setViewName(\"login\");\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/config/WebSecurityConfig.java",
    "content": "package com.us.example.config;\n\nimport com.us.example.security.CustomUserService;\nimport com.us.example.util.MD5Util;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\n@EnableWebSecurity\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Bean\n    UserDetailsService customUserService(){ //注册UserDetailsService 的bean\n        return new CustomUserService();\n    }\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserService()).passwordEncoder(new PasswordEncoder(){\n\n            @Override\n            public String encode(CharSequence rawPassword) {\n                return MD5Util.encode((String)rawPassword);\n            }\n\n            @Override\n            public boolean matches(CharSequence rawPassword, String encodedPassword) {\n                return encodedPassword.equals(MD5Util.encode((String)rawPassword));\n            }}); //user Details Service验证\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.authorizeRequests()\n                .anyRequest().authenticated() //任何请求,登录后可以访问\n                .and()\n                .formLogin()\n                .loginPage(\"/login\")\n                .failureUrl(\"/login?error\")\n                .permitAll() //登录页面用户任意访问\n                .and()\n                .logout().permitAll(); //注销行为任意访问\n\n\n    }\n\n\n\n}\n\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/controller/HomeController.java",
    "content": "package com.us.example.controller;\n\nimport com.us.example.domain.Msg;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Controller\npublic class HomeController {\n\n    @RequestMapping(\"/\")\n    public String index(Model model){\n        Msg msg =  new Msg(\"测试标题\",\"测试内容\",\"额外信息，只对管理员显示\");\n        model.addAttribute(\"msg\", msg);\n        return \"home\";\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/dao/UserDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.SysUser;\n\n\npublic interface UserDao {\n    public SysUser findByUserName(String username);\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/domain/Msg.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n    public class Msg {\n        private String title;\n        private String content;\n        private String etraInfo;\n\n        public Msg(String title, String content, String etraInfo) {\n            super();\n            this.title = title;\n            this.content = content;\n            this.etraInfo = etraInfo;\n        }\n        public String getTitle() {\n            return title;\n        }\n        public void setTitle(String title) {\n            this.title = title;\n        }\n        public String getContent() {\n            return content;\n        }\n        public void setContent(String content) {\n            this.content = content;\n        }\n        public String getEtraInfo() {\n            return etraInfo;\n        }\n        public void setEtraInfo(String etraInfo) {\n            this.etraInfo = etraInfo;\n        }\n\n    }\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/domain/SysRole.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysRole {\n\n    private Integer id;\n    private String name;\n    public Integer getId() {\n        return id;\n    }\n    public void setId(Integer id) {\n        this.id = id;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/domain/SysUser.java",
    "content": "package com.us.example.domain;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysUser {\n    private Integer id;\n    private String username;\n    private String password;\n\n    private List<SysRole> roles;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public List<SysRole> getRoles() {\n        return roles;\n    }\n\n    public void setRoles(List<SysRole> roles) {\n        this.roles = roles;\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/security/CustomUserService.java",
    "content": "package com.us.example.security;\n\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.SysRole;\nimport com.us.example.domain.SysUser;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Service\npublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口\n\n    @Autowired\n    UserDao userDao;\n\n    @Override\n    public UserDetails loadUserByUsername(String username) { //重写loadUserByUsername 方法获得 userdetails 类型用户\n\n        SysUser user = userDao.findByUserName(username);\n        if(user == null){\n            throw new UsernameNotFoundException(\"用户名不存在\");\n        }\n        List<SimpleGrantedAuthority> authorities = new ArrayList<>();\n        //用于添加用户的权限。只要把用户权限添加到authorities 就万事大吉。\n        for(SysRole role:user.getRoles())\n        {\n            authorities.add(new SimpleGrantedAuthority(role.getName()));\n            System.out.println(role.getName());\n        }\n        return new org.springframework.security.core.userdetails.User(user.getUsername(),\n                user.getPassword(), authorities);\n\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/java/com/us/example/util/MD5Util.java",
    "content": "package com.us.example.util;\n\n/**\n * Created by yangyibo on 17/2/7.\n */\nimport java.security.MessageDigest;\n/**\n * MD5加密工具\n *\n */\npublic class MD5Util {\n\n    private static final String SALT = \"tamboo\";\n\n    public static String encode(String password) {\n        password = password + SALT;\n        MessageDigest md5 = null;\n        try {\n            md5 = MessageDigest.getInstance(\"MD5\");\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n        char[] charArray = password.toCharArray();\n        byte[] byteArray = new byte[charArray.length];\n\n        for (int i = 0; i < charArray.length; i++)\n            byteArray[i] = (byte) charArray[i];\n        byte[] md5Bytes = md5.digest(byteArray);\n        StringBuffer hexValue = new StringBuffer();\n        for (int i = 0; i < md5Bytes.length; i++) {\n            int val = ((int) md5Bytes[i]) & 0xff;\n            if (val < 16) {\n                hexValue.append(\"0\");\n            }\n\n            hexValue.append(Integer.toHexString(val));\n        }\n        return hexValue.toString();\n    }\n\n    public static void main(String[] args) {\n        System.out.println(MD5Util.encode(\"abel\"));\n\n\n    }\n}"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?characterEncoding=utf-8&useSSL=false\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\n\r\n\r\nlogging.level.org.springframework.security= INFO\r\nspring.thymeleaf.cache=false\r\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.us.example.domain.SysUser\">\n        <id property=\"id\" column=\"ID\"/>\n        <result property=\"username\" column=\"username\"/>\n        <result property=\"password\" column=\"PASSWORD\"/>\n        <collection property=\"roles\" ofType=\"com.us.example.domain.SysRole\">\n            <result column=\"name\" property=\"name\"/>\n        </collection>\n\n    </resultMap>\n    <select id=\"findByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        where username= #{username}\n\t</select>\n</mapper>"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/resources/templates/home.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\" \n\t  xmlns:sec=\"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title sec:authentication=\"name\"></title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\" />\n<style type=\"text/css\">\nbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n    \n    \n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n      \t<h1 th:text=\"${msg.title}\"></h1>\n\t\t\n\t\t<p class=\"bg-primary\" th:text=\"${msg.content}\"></p>\n\t\t\n\t\t<div sec:authorize=\"hasRole('ROLE_ADMIN')\"> <!-- 用户类型为ROLE_ADMIN 显示 -->\n\t\t \t<p class=\"bg-info\" th:text=\"${msg.etraInfo}\"></p>\n\t\t</div>\t\n\t\t\n\t\t<div sec:authorize=\"hasRole('ROLE_USER')\"> <!-- 用户类型为 ROLE_USER 显示 -->\n\t\t \t<p class=\"bg-info\">无更多信息显示</p>\n\t\t</div>\t\n\t\t\n        <form th:action=\"@{/logout}\" method=\"post\">\n            <input type=\"submit\" class=\"btn btn-primary\" value=\"注销\"/>\n        </form>\n      </div>\n\n    </div>\n    \n\t\n</body>\n</html>\n"
  },
  {
    "path": "springboot-SpringSecurity0/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title>登录页面</title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\"/>\n<style type=\"text/css\">\n\tbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n           \n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n       <p th:if=\"${param.logout}\" class=\"bg-warning\">已成功注销</p><!-- 1 -->\n\t\t\t<p th:if=\"${param.error}\" class=\"bg-danger\">有错误，请重试</p> <!-- 2 -->\n\t\t\t<h2>使用账号密码登录</h2>\n\t\t\t<form name=\"form\" th:action=\"@{/login}\" action=\"/login\" method=\"POST\"> <!-- 3 -->\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"username\">账号</label>\n\t\t\t\t\t<input type=\"text\" class=\"form-control\" name=\"username\" value=\"\" placeholder=\"账号\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"password\">密码</label>\n\t\t\t\t\t<input type=\"password\" class=\"form-control\" name=\"password\" placeholder=\"密码\" />\n\t\t\t\t</div>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n      </div>\n\n    </div>\n\t\t\n</body>\n</html>"
  },
  {
    "path": "springboot-SpringSecurity1/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-security1</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.example.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.thymeleaf.extras</groupId>\n            <artifactId>thymeleaf-extras-springsecurity4</artifactId>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n\n    </dependencies>\n    <build>\n        <plugins>\n\n            <!--&lt;!&ndash;打依赖包&ndash;&gt;-->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-shade-plugin</artifactId>\n                <version>2.3</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>shade</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/config/DBconfig.java",
    "content": "package com.us.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\npublic class DBconfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/config/MyBatisConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class MyBatisConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"sqlSessionFactory\")\n    public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {\n        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        // sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n        sessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n        return sessionFactory;\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/config/MyBatisScannerConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/config/TransactionConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/config/WebSecurityConfig.java",
    "content": "package com.us.example.config;\n\nimport com.us.example.service.CustomUserService;\nimport com.us.example.service.MyFilterSecurityInterceptor;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.web.access.intercept.FilterSecurityInterceptor;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n\n\n@Configuration\n@EnableWebSecurity\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;\n    @Autowired\n    UserDetailsService customUserService;\n\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserService); //user Details Service验证\n\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.authorizeRequests()\n                .antMatchers(\"/css/**\").permitAll()\n                .anyRequest().authenticated() //任何请求,登录后可以访问\n                .and()\n                .formLogin()\n                .loginPage(\"/login\")\n                .defaultSuccessUrl(\"/\")\n                .failureUrl(\"/login?error\")\n                .permitAll() //登录页面用户任意访问\n                .and()\n                .logout().permitAll(); //注销行为任意访问\n        http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);\n    }\n\n}\n\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/controller/HomeController.java",
    "content": "package com.us.example.controller;\n\nimport com.us.example.domain.Msg;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Controller\npublic class HomeController {\n\n    @RequestMapping(\"/\")\n    public String index(Model model){\n        Msg msg =  new Msg(\"测试标题\",\"测试内容\",\"欢迎来到HOME页面,您拥有 ROLE_HOME 权限\");\n        model.addAttribute(\"msg\", msg);\n        return \"home\";\n    }\n\n    @RequestMapping(\"/login\")\n    public  String login(){\n        return \"login\";\n    }\n\n    @RequestMapping(\"/admin\")\n    @ResponseBody\n    public String hello(){\n        return \"hello admin\";\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/dao/PermissionDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.Permission;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/20.\n */\npublic interface PermissionDao {\n    public List<Permission> findAll();\n    public List<Permission> findByAdminUserId(int userId);\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/dao/UserDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.SysUser;\n\n\npublic interface UserDao {\n    public SysUser findByUserName(String username);\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/domain/Msg.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n    public class Msg {\n        private String title;\n        private String content;\n        private String etraInfo;\n\n        public Msg(String title, String content, String etraInfo) {\n            super();\n            this.title = title;\n            this.content = content;\n            this.etraInfo = etraInfo;\n        }\n        public String getTitle() {\n            return title;\n        }\n        public void setTitle(String title) {\n            this.title = title;\n        }\n        public String getContent() {\n            return content;\n        }\n        public void setContent(String content) {\n            this.content = content;\n        }\n        public String getEtraInfo() {\n            return etraInfo;\n        }\n        public void setEtraInfo(String etraInfo) {\n            this.etraInfo = etraInfo;\n        }\n\n    }\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/domain/Permission.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/20.\n */\npublic class Permission {\n\n    private int id;\n    //权限名称\n    private String name;\n\n    //权限描述\n    private String descritpion;\n\n    //授权链接\n    private String url;\n\n    //父节点id\n    private int pid;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDescritpion() {\n        return descritpion;\n    }\n\n    public void setDescritpion(String descritpion) {\n        this.descritpion = descritpion;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public int getPid() {\n        return pid;\n    }\n\n    public void setPid(int pid) {\n        this.pid = pid;\n    }\n\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/domain/SysRole.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysRole {\n\n    private Integer id;\n    private String name;\n    public Integer getId() {\n        return id;\n    }\n    public void setId(Integer id) {\n        this.id = id;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/domain/SysUser.java",
    "content": "package com.us.example.domain;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysUser {\n    private Integer id;\n    private String username;\n    private String password;\n\n    private List<SysRole> roles;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public List<SysRole> getRoles() {\n        return roles;\n    }\n\n    public void setRoles(List<SysRole> roles) {\n        this.roles = roles;\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/service/CustomUserService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.dao.PermissionDao;\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.Permission;\nimport com.us.example.domain.SysRole;\nimport com.us.example.domain.SysUser;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Service\npublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口\n\n    @Autowired\n    UserDao userDao;\n    @Autowired\n    PermissionDao permissionDao;\n\n    public UserDetails loadUserByUsername(String username) {\n        SysUser user = userDao.findByUserName(username);\n        if (user != null) {\n            List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());\n            List<GrantedAuthority> grantedAuthorities = new ArrayList <>();\n            for (Permission permission : permissions) {\n                if (permission != null && permission.getName()!=null) {\n\n                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());\n                grantedAuthorities.add(grantedAuthority);\n                }\n            }\n            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);\n        } else {\n            throw new UsernameNotFoundException(\"admin: \" + username + \" do not exist!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/service/MyAccessDecisionManager.java",
    "content": "package com.us.example.service;\n\nimport org.springframework.security.access.AccessDecisionManager;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.authentication.InsufficientAuthenticationException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Collection;\nimport java.util.Iterator;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyAccessDecisionManager implements AccessDecisionManager {\n    @Override\n    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {\n\n        if(null== configAttributes || configAttributes.size() <=0) {\n            return;\n        }\n        ConfigAttribute c;\n        String needRole;\n        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {\n            c = iter.next();\n            needRole = c.getAttribute();\n            for(GrantedAuthority ga : authentication.getAuthorities()) {\n                if(needRole.trim().equals(ga.getAuthority())) {\n                    return;\n                }\n            }\n        }\n        throw new AccessDeniedException(\"no right\");\n    }\n\n\n\n    @Override\n    public boolean supports(ConfigAttribute attribute) {\n        return true;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/service/MyFilterSecurityInterceptor.java",
    "content": "package com.us.example.service;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.SecurityMetadataSource;\nimport org.springframework.security.access.intercept.AbstractSecurityInterceptor;\nimport org.springframework.security.access.intercept.InterceptorStatusToken;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.stereotype.Service;\n\nimport java.io.IOException;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {\n\n\n    @Autowired\n    private FilterInvocationSecurityMetadataSource securityMetadataSource;\n\n    @Autowired\n    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {\n        super.setAccessDecisionManager(myAccessDecisionManager);\n    }\n\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\n        FilterInvocation fi = new FilterInvocation(request, response, chain);\n        invoke(fi);\n    }\n\n\n    public void invoke(FilterInvocation fi) throws IOException, ServletException {\n//fi里面有一个被拦截的url\n//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限\n//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够\n        InterceptorStatusToken token = super.beforeInvocation(fi);\n        try {\n//执行下一个拦截器\n            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());\n        } finally {\n            super.afterInvocation(token, null);\n        }\n    }\n\n\n    @Override\n    public void destroy() {\n\n    }\n\n    @Override\n    public Class<?> getSecureObjectClass() {\n        return FilterInvocation.class;\n\n    }\n\n    @Override\n    public SecurityMetadataSource obtainSecurityMetadataSource() {\n        return this.securityMetadataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/java/com/us/example/service/MyInvocationSecurityMetadataSourceService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.dao.PermissionDao;\nimport com.us.example.domain.Permission;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.access.SecurityConfig;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.*;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyInvocationSecurityMetadataSourceService  implements\n        FilterInvocationSecurityMetadataSource {\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    private HashMap<String, Collection<ConfigAttribute>> map =null;\n\n    /**\n     * 加载资源，初始化资源变量\n     */\n    public void loadResourceDefine(){\n        map = new HashMap<>();\n        Collection<ConfigAttribute> array;\n        ConfigAttribute cfg;\n        List<Permission> permissions = permissionDao.findAll();\n        for(Permission permission : permissions) {\n            array = new ArrayList<>();\n            cfg = new SecurityConfig(permission.getName());\n            array.add(cfg);\n            map.put(permission.getUrl(), array);\n        }\n\n    }\n\n    @Override\n    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {\n        if(map ==null) loadResourceDefine();\n        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();\n        AntPathRequestMatcher matcher;\n        String resUrl;\n        for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {\n            resUrl = iter.next();\n            matcher = new AntPathRequestMatcher(resUrl);\n            if(matcher.matches(request)) {\n                return map.get(resUrl);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public Collection<ConfigAttribute> getAllConfigAttributes() {\n        return null;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?characterEncoding=utf-8&useSSL=false\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\n\r\nserver.port=8081\r\nlogging.level.org.springframework.security= INFO\r\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/resources/mapper/PermissionDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.PermissionDao\">\n<select id=\"findAll\"  resultType=\"com.us.example.domain.Permission\">\n\n   SELECT * from Sys_permission ;\n</select>\n\n <select id=\"findByAdminUserId\" parameterType=\"int\" resultType=\"com.us.example.domain.Permission\">\n      select p.*\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        LEFT JOIN Sys_permission_role spr on spr.role_id=r.id\n        LEFT JOIN Sys_permission p on p.id =spr.permission_id\n        where u.id=#{userId}\n </select>\n </mapper>"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.us.example.domain.SysUser\">\n        <id property=\"id\" column=\"ID\"/>\n        <result property=\"username\" column=\"username\"/>\n        <result property=\"password\" column=\"PASSWORD\"/>\n        <collection property=\"roles\" ofType=\"com.us.example.domain.SysRole\">\n            <result column=\"name\" property=\"name\"/>\n        </collection>\n\n    </resultMap>\n    <select id=\"findByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        where username= #{username}\n\t</select>\n</mapper>"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/resources/templates/home.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\" \n\t  xmlns:sec=\"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title sec:authentication=\"name\"></title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\" />\n<style type=\"text/css\">\nbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n              <li><a sec:authorize=\"hasRole('ROLE_ADMIN')\" th:href=\"@{/admin}\"> admin </a></li>\n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n    \n    \n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n      \t<h1 th:text=\"${msg.title}\"></h1>\n\t\t\n\t\t<p class=\"bg-primary\" th:text=\"${msg.content}\"></p>\n\t\t\n\t\t<div sec:authorize=\"hasRole('ROLE_HOME')\"> <!-- 用户类型为ROLE_ADMIN 显示 -->\n\t\t \t<p class=\"bg-info\" th:text=\"${msg.etraInfo}\"></p>\n\t\t</div>\n          <div sec:authorize=\"hasRole('ROLE_ADMIN')\"> <!-- 用户类型为ROLE_ADMIN 显示 -->\n              <p class=\"bg-info\">恭喜您,您有 ROLE_ADMIN 权限 </p>\n          </div>\n\n          <form th:action=\"@{/logout}\" method=\"post\">\n            <input type=\"submit\" class=\"btn btn-primary\" value=\"注销\"/>\n        </form>\n      </div>\n\n    </div>\n    \n\t\n</body>\n</html>\n"
  },
  {
    "path": "springboot-SpringSecurity1/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\"\n      xmlns:sec=\"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title>登录页面</title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\"/>\n<style type=\"text/css\">\n\tbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n           \n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n       <p th:if=\"${param.logout}\" class=\"bg-warning\">已成功注销</p><!-- 1 -->\n\t\t\t<p th:if=\"${param.error}\" class=\"bg-danger\">有错误，请重试</p> <!-- 2 -->\n\t\t\t<h2>使用账号密码登录</h2>\n\t\t\t<form name=\"form\" th:action=\"@{/login}\" action=\"/login\" method=\"POST\"> <!-- 3 -->\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"username\">账号</label>\n\t\t\t\t\t<input type=\"text\" class=\"form-control\" name=\"username\" value=\"\" placeholder=\"账号\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"password\">密码</label>\n\t\t\t\t\t<input type=\"password\" class=\"form-control\" name=\"password\" placeholder=\"密码\" />\n\t\t\t\t</div>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n      </div>\n\n    </div>\n\t\t\n</body>\n</html>"
  },
  {
    "path": "springboot-dubbo/README.md",
    "content": "##springboot-dubbo\n\n该项目是Springboot 和 dubbo 结合的例子，是provider 的示例，提供服务。简单的写了一些用户和权限的接口没有写的很完整，主要是为了提现dubbo 服务\nSpringboot-shiro2 也是和dubbo 的结合例子是 消费者的示例。\n\n### abel-user-api\n该模块是让消费者 引用的 api 模块，主要用来定义接口和数据传输实体\n\n### abel-user-provider\n该模块是真正的微服务提供者\n"
  },
  {
    "path": "springboot-dubbo/abel-user-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>cn.abel</groupId>\n        <artifactId>abel-parent</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n  \n    <groupId>cn.abel</groupId>\n    <artifactId>abel-user-api</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/models/Permission.java",
    "content": "package cn.abel.user.models;\n\n\nimport java.io.Serializable;\n\npublic class Permission implements Serializable {\n\n    private static final long serialVersionUID = 2079120477173696231L;\n    private Integer id;\n    private String name;\n    private String permissionUrl;\n    private String method;\n    private String description;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPermissionUrl() {\n        return permissionUrl;\n    }\n\n    public void setPermissionUrl(String permissionUrl) {\n        this.permissionUrl = permissionUrl;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"Permission{\" +\n                \"id=\" + id +\n                \", name=\" + name +\n                \", permissionUrl=\" + permissionUrl +\n                \", method=\" + method +\n                \", description=\" + description +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/models/Role.java",
    "content": "package cn.abel.user.models;\n\n\nimport java.io.Serializable;\n\npublic class Role implements Serializable {\n\n    private static final long serialVersionUID = -4873217276773065821L;\n    private Integer id;\n    private String name;\n    private Integer roleLevel;\n    private String description;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getRoleLevel() {\n        return roleLevel;\n    }\n\n    public void setRoleLevel(Integer roleLevel) {\n        this.roleLevel = roleLevel;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"Role{\" +\n                \"id=\" + id +\n                \", name=\" + name +\n                \", roleLevel=\" + roleLevel +\n                \", description=\" + description +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/models/User.java",
    "content": "package cn.abel.user.models;\n\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = -4523695542426439365L;\n    private Integer id;\n    private String cnname;\n    private String username;\n\n    @JsonIgnore\n    private String password;\n    private String email;\n    private String mobilePhone;\n\n\n    private List<Role> roles;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getCnname() {\n        return cnname;\n    }\n\n    public void setCnname(String cnname) {\n        this.cnname = cnname;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n\n    public String getMobilePhone() {\n        return mobilePhone;\n    }\n\n    public void setMobilePhone(String mobilePhone) {\n        this.mobilePhone = mobilePhone;\n    }\n\n    public List<Role> getRoles() {\n        return roles;\n    }\n\n    public void setRoles(List<Role> roles) {\n        this.roles = roles;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id=\" + id +\n                \", cnname=\" + cnname +\n                \", username=\" + username +\n                \", password=\" + password +\n                \", email=\" + email +\n                \", mobilePhone=\" + mobilePhone +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/service/PermissionService.java",
    "content": "package cn.abel.user.service;\n\nimport cn.abel.user.models.Permission;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface PermissionService {\n\n    List<Permission> getByMap(Map<String, Object> map);\n\n    Permission getById(Integer id);\n\n    Permission create(Permission permission);\n\n\n    Permission update(Permission permission);\n\n    int delete(Integer id);\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/service/RoleService.java",
    "content": "package cn.abel.user.service;\n\n\nimport cn.abel.user.models.Role;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface RoleService {\n\n\n    List<Role> getByMap(Map<String, Object> map);\n\n    Role getById(Integer id);\n\n    Role create(Role role);\n\n    Role update(Role role);\n\n    int delete(Integer id);\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-api/src/main/java/cn/abel/user/service/UserService.java",
    "content": "package cn.abel.user.service;\n\nimport cn.abel.user.models.User;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface UserService {\n\n    List<User> getByMap(Map<String, Object> map);\n\n    User getById(Integer id);\n\n    User create(User user);\n\n    User update(User user);\n\n    int delete(Integer id);\n\n    User getByUserName(String userName);\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/doc/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50719\n Source Host           : 127.0.0.1:3306\n Source Schema         : shiro\n\n Target Server Type    : MySQL\n Target Server Version : 50719\n File Encoding         : 65001\n\n Date: 20/03/2020 10:51:00\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for permission\n-- ----------------------------\nDROP TABLE IF EXISTS `permission`;\nCREATE TABLE `permission` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` varchar(100) COLLATE utf8_bin NOT NULL,\n  `permission_url` varchar(100) COLLATE utf8_bin DEFAULT NULL,\n  `method` varchar(100) COLLATE utf8_bin DEFAULT NULL,\n  `description` varchar(1000) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name` (`name`)\n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Table structure for role\n-- ----------------------------\nDROP TABLE IF EXISTS `role`;\nCREATE TABLE `role` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` varchar(100) COLLATE utf8_bin NOT NULL,\n  `role_level` int(1) DEFAULT NULL,\n  `description` varchar(1000) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name` (`name`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Table structure for role_permission\n-- ----------------------------\nDROP TABLE IF EXISTS `role_permission`;\nCREATE TABLE `role_permission` (\n  `role_id` int(11) NOT NULL,\n  `permission_id` int(11) NOT NULL,\n  PRIMARY KEY (`role_id`,`permission_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Table structure for user\n-- ----------------------------\nDROP TABLE IF EXISTS `user`;\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `cnname` varchar(50) COLLATE utf8_bin DEFAULT NULL,\n  `username` varchar(50) COLLATE utf8_bin NOT NULL,\n  `password` varchar(100) COLLATE utf8_bin NOT NULL,\n  `email` varchar(100) COLLATE utf8_bin DEFAULT NULL,\n  `mobile_phone` varchar(50) COLLATE utf8_bin DEFAULT NULL,\n  `status` int(11) DEFAULT '4' COMMENT '用户登录状态,1 : 在线 2 离开 3 忙碌 4 离线',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username` (`username`)\n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Table structure for user_role\n-- ----------------------------\nDROP TABLE IF EXISTS `user_role`;\nCREATE TABLE `user_role` (\n  `user_id` int(11) NOT NULL,\n  `role_id` int(11) NOT NULL,\n  PRIMARY KEY (`user_id`,`role_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>cn.abel</groupId>\n        <artifactId>abel-parent</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>abel-user-provider</artifactId>\n    <version>1.0.0</version>\n    <packaging>jar</packaging>\n\n    <dependencies>\n\n        <dependency>\n            <groupId>cn.abel</groupId>\n            <artifactId>abel-user-api</artifactId>\n            <version>1.0.0-SNAPSHOT</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.abel</groupId>\n            <artifactId>abel-util</artifactId>\n            <version>1.0.0-SNAPSHOT</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.58</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-collections4</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <!--dubbox-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>dubbo</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.resteasy</groupId>\n            <artifactId>resteasy-jaxrs</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.resteasy</groupId>\n            <artifactId>resteasy-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.resteasy</groupId>\n            <artifactId>resteasy-jackson-provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>javax.validation</groupId>\n            <artifactId>validation-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate.validator</groupId>\n            <artifactId>hibernate-validator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.101tec</groupId>\n            <artifactId>zkclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpcore</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpcore-nio</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpasyncclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>it.uniroma1.dis.wsngroup.gexf4j</groupId>\n            <artifactId>gexf4j</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.sentry</groupId>\n            <artifactId>sentry-logback</artifactId>\n            <version>1.7.3</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-framework</artifactId>\n            <version>2.5.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.javassist</groupId>\n            <artifactId>javassist</artifactId>\n            <version>3.15.0-GA</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/UserProviderApplication.java",
    "content": "package cn.abel.user;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ImportResource;\n\n@SpringBootApplication\n@ImportResource(\"classpath*:META-INF/spring/*.xml\")\npublic class UserProviderApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(UserProviderApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/constants/Constants.java",
    "content": "package cn.abel.user.constants;\n\n/**\n * 公用的常量类。\n */\npublic interface Constants {\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/dao/PermissionDao.java",
    "content": "package cn.abel.user.dao;\n\n\nimport cn.abel.user.models.Permission;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Repository\n@Mapper\npublic interface PermissionDao {\n\n    List<Permission> getByMap(Map<String, Object> map);\n\n    Permission getById(Integer id);\n\n    Integer create(Permission permission);\n\n    int update(Permission permission);\n\n    int delete(Integer id);\n\n    List<Permission> getList();\n\n    List<Permission> getByUserId(Integer userId);\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/dao/RoleDao.java",
    "content": "package cn.abel.user.dao;\n\n\n\nimport cn.abel.user.models.Role;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\nimport java.util.Map;\n@Repository\n@Mapper\npublic interface RoleDao {\n\n\tList<Role> getByMap(Map<String, Object> map);\n\tRole getById(Integer id);\n\tInteger create(Role role);\n\tint update(Role role);\n\tint delete(Integer id);\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/dao/UserDao.java",
    "content": "package cn.abel.user.dao;\n\n\nimport cn.abel.user.models.User;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\nimport java.util.Map;\n@Repository\n@Mapper\npublic interface UserDao {\n\n\tList<User> getByMap(Map<String, Object> map);\n\tUser getById(Integer id);\n\tInteger create(User user);\n\tint update(User user);\n\tint delete(Integer id);\n\tUser getByUserName(String userName);\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/exception/JsonExceptionMapper.java",
    "content": "package cn.abel.user.exception;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\nimport cn.abel.code.InfoCode;\nimport cn.abel.response.ResponseEntity;\nimport org.codehaus.jackson.JsonProcessingException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * json转换错误\n *\n * @author ye\n * @date 2018/11/02 14:20\n */\npublic class JsonExceptionMapper implements ExceptionMapper<JsonProcessingException> {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(JsonExceptionMapper.class);\n\n    @Override\n    public Response toResponse(JsonProcessingException exception) {\n        ResponseEntity entity = ResponseEntity.error(InfoCode.REQUEST_PARAM_ERROR);\n        logger.info(\"{}\", InfoCode.REQUEST_PARAM_ERROR.getMsg());\n        return Response.ok(entity, MediaType.APPLICATION_JSON).build();\n    }\n\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/exception/ReaderExceptionMapper.java",
    "content": "package cn.abel.user.exception;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\nimport cn.abel.code.InfoCode;\nimport cn.abel.response.ResponseEntity;\nimport org.jboss.resteasy.spi.ReaderException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * json转换错误\n *\n * @author ye\n * @date 2018/11/02 14:20\n */\npublic class ReaderExceptionMapper implements ExceptionMapper<ReaderException> {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(ReaderExceptionMapper.class);\n\n    @Override\n    public Response toResponse(ReaderException exception) {\n        ResponseEntity entity = ResponseEntity.error(InfoCode.REQUEST_PARAM_ERROR);\n        logger.info(\"{}\", InfoCode.REQUEST_PARAM_ERROR.getMsg());\n        return Response.ok(entity, MediaType.APPLICATION_JSON).build();\n    }\n\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/exception/RestExceptionMapper.java",
    "content": "package cn.abel.user.exception;\n\nimport javax.ws.rs.NotAllowedException;\nimport javax.ws.rs.NotFoundException;\nimport javax.ws.rs.NotSupportedException;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * http调用错误\n *\n * @author ye\n * @date 2018/11/02 14:20\n */\npublic class RestExceptionMapper implements ExceptionMapper<WebApplicationException> {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(WebApplicationException.class);\n\n    @Override\n    public Response toResponse(WebApplicationException e) {\n        if (e instanceof NotAllowedException) {\n            logger.info(\"method错误。{}\", e.getMessage());\n            return null;\n        }\n\n        //415\n        if (e instanceof NotSupportedException) {\n            logger.info(\"content-type错误。{}\", e.getMessage());\n            return null;\n        }\n\n        if (e instanceof NotFoundException) {\n            logger.info(\"url错误。{}\", e.getMessage());\n            return null;\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/exception/ServiceExceptionMapper.java",
    "content": "package cn.abel.user.exception;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\nimport cn.abel.exception.ServiceException;\nimport cn.abel.response.ResponseEntity;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * ServiceExceptionMapper\n *\n * @author ye\n * @date 2018/11/02 14:20\n */\npublic class ServiceExceptionMapper implements ExceptionMapper<ServiceException> {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(ServiceException.class);\n\n    @Override\n    public Response toResponse(ServiceException exception) {\n        ResponseEntity entity = ResponseEntity.error(exception.getErrorCode(), exception.getMessage());\n        logger.error(\"{}，{}\", exception.getErrorCode(), exception.getMessage());\n        return Response.ok(entity, MediaType.APPLICATION_JSON).build();\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/exception/ValidationExceptionMapper.java",
    "content": "package cn.abel.user.exception;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.ConstraintViolationException;\nimport javax.ws.rs.core.Response;\n\nimport cn.abel.code.InfoCode;\nimport cn.abel.response.ResponseEntity;\nimport com.alibaba.dubbo.rpc.protocol.rest.RpcExceptionMapper;\nimport com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;\n\n/**\n * 参数校验异常\n *\n * @author ye\n * @date 2018/11/04 16:53\n */\npublic class ValidationExceptionMapper extends RpcExceptionMapper {\n\n    @Override\n    protected Response handleConstraintViolationException(ConstraintViolationException cve) {\n        //ViolationReport report = new ViolationReport();\n        String msg = \"\";\n        for (ConstraintViolation cv : cve.getConstraintViolations()) {\n            //report.addConstraintViolation(new RestConstraintViolation(cv.getPropertyPath().toString(),\n            //        cv.getMessage(), cv.getInvalidValue() == null ? \"null\" : cv.getInvalidValue().toString()));\n            msg = cv.getPropertyPath().toString() + \" \" + cv.getMessage();\n        }\n\n        ResponseEntity entity = ResponseEntity.error(InfoCode.REQUEST_PARAM_ERROR.getStatus(),\n                InfoCode.REQUEST_PARAM_ERROR.getMsg() + \"(\" + msg + \")\");\n\n        // 采用json输出代替xml输出\n        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(entity).type(ContentType.APPLICATION_JSON_UTF_8).build();\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/filter/RestFilter.java",
    "content": "package cn.abel.user.filter;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.annotation.Priority;\nimport javax.ws.rs.client.ClientRequestContext;\nimport javax.ws.rs.client.ClientRequestFilter;\nimport javax.ws.rs.client.ClientResponseContext;\nimport javax.ws.rs.client.ClientResponseFilter;\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.container.ContainerRequestFilter;\nimport javax.ws.rs.container.ContainerResponseContext;\nimport javax.ws.rs.container.ContainerResponseFilter;\nimport javax.ws.rs.container.PreMatching;\nimport javax.ws.rs.core.MultivaluedMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 日志-复制并替代com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter\n *\n * @author ye\n * @date 2018/11/02 15:20\n */\n@Priority(900)\n@PreMatching\npublic class RestFilter implements ContainerRequestFilter, ClientRequestFilter, ContainerResponseFilter,\n        ClientResponseFilter {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(RestFilter.class);\n\n    @Override\n    public void filter(ClientRequestContext context) throws IOException {\n        logHttpHeaders(context.getStringHeaders());\n    }\n\n    @Override\n    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {\n        logHttpHeaders(responseContext.getHeaders());\n    }\n\n    @Override\n    public void filter(ContainerRequestContext context) throws IOException {\n        logHttpHeaders(context.getHeaders());\n    }\n\n    @Override\n    public void filter(ContainerRequestContext requestContext,\n                       ContainerResponseContext responseContext) throws IOException {\n        logHttpHeaders(responseContext.getStringHeaders());\n    }\n\n    protected void logHttpHeaders(MultivaluedMap<String, String> headers) {\n        StringBuilder msg = new StringBuilder(\"The HTTP headers are: \\n\");\n        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {\n            msg.append(entry.getKey()).append(\": \");\n            for (int i = 0; i < entry.getValue().size(); i++) {\n                msg.append(entry.getValue().get(i));\n                if (i < entry.getValue().size() - 1) {\n                    msg.append(\", \");\n                }\n            }\n            msg.append(\"\\n\");\n        }\n        logger.info(msg.toString());\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/filter/RestInterceptor.java",
    "content": "package cn.abel.user.filter;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.ext.ReaderInterceptor;\nimport javax.ws.rs.ext.ReaderInterceptorContext;\nimport javax.ws.rs.ext.WriterInterceptor;\nimport javax.ws.rs.ext.WriterInterceptorContext;\n\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 日志-复制并替代com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter\n *\n * @author ye\n * @date 2018/11/04 16:34\n */\npublic class RestInterceptor implements WriterInterceptor, ReaderInterceptor {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(RestInterceptor.class);\n\n    @Override\n    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {\n        byte[] buffer = IOUtils.toByteArray(context.getInputStream());\n        logger.info(\"The contents of request body is: \\n\" + new String(buffer, \"UTF-8\") + \"\\n\");\n        context.setInputStream(new ByteArrayInputStream(buffer));\n        return context.proceed();\n    }\n\n    @Override\n    public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {\n        RestInterceptor.OutputStreamWrapper wrapper =\n                new RestInterceptor.OutputStreamWrapper(context.getOutputStream());\n        context.setOutputStream(wrapper);\n        context.proceed();\n        logger.info(\"The contents of response body is: \\n\" + new String(wrapper.getBytes(), \"UTF-8\") + \"\\n\");\n    }\n\n    protected static class OutputStreamWrapper extends OutputStream {\n\n        private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        private final OutputStream output;\n\n        private OutputStreamWrapper(OutputStream output) {\n            this.output = output;\n        }\n\n        @Override\n        public void write(int i) throws IOException {\n            buffer.write(i);\n            output.write(i);\n        }\n\n        @Override\n        public void write(byte[] b) throws IOException {\n            buffer.write(b);\n            output.write(b);\n        }\n\n        @Override\n        public void write(byte[] b, int off, int len) throws IOException {\n            buffer.write(b, off, len);\n            output.write(b, off, len);\n        }\n\n        @Override\n        public void flush() throws IOException {\n            output.flush();\n        }\n\n        @Override\n        public void close() throws IOException {\n            output.close();\n        }\n\n        public byte[] getBytes() {\n            return buffer.toByteArray();\n        }\n    }\n\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/service/impl/PermissionServiceImpl.java",
    "content": "package cn.abel.user.service.impl;\n\nimport cn.abel.user.dao.PermissionDao;\nimport cn.abel.user.models.Permission;\nimport cn.abel.user.service.PermissionService;\nimport com.alibaba.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service(protocol = {\"dubbo\"}, validation = \"false\")\npublic class PermissionServiceImpl implements PermissionService {\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Override\n    public List<Permission> getByMap(Map<String, Object> map) {\n        return permissionDao.getByMap(map);\n    }\n\n    @Override\n    public Permission getById(Integer id) {\n        return permissionDao.getById(id);\n    }\n\n    @Override\n    public Permission create(Permission permission) {\n        permissionDao.create(permission);\n        return permission;\n    }\n\n    @Override\n    public Permission update(Permission permission) {\n        permissionDao.update(permission);\n        return permission;\n    }\n\n    @Override\n    public int delete(Integer id) {\n        return permissionDao.delete(id);\n    }\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/service/impl/RoleServiceImpl.java",
    "content": "package cn.abel.user.service.impl;\n\n\nimport cn.abel.user.dao.RoleDao;\nimport cn.abel.user.models.Role;\nimport cn.abel.user.service.RoleService;\nimport com.alibaba.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service(protocol = {\"dubbo\"}, validation = \"false\")\npublic class RoleServiceImpl implements RoleService{\n    @Autowired\n\tprivate RoleDao roleDao;\n\t@Override\n\tpublic List<Role> getByMap(Map<String,Object> map) {\n\t    return roleDao.getByMap(map);\n\t}\n\t@Override\n\tpublic Role getById(Integer id) {\n\t\treturn roleDao.getById(id);\n\t}\n\t@Override\n\tpublic Role create(Role role) {\n\t\troleDao.create(role);\n\t\treturn role;\n\t}\n\t@Override\n\tpublic Role update(Role role) {\n\t\troleDao.update(role);\n\t\treturn role;\n\t}\n\t@Override\n\tpublic int delete(Integer id) {\n\t\treturn roleDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/service/impl/UserServiceImpl.java",
    "content": "package cn.abel.user.service.impl;\n\nimport cn.abel.user.dao.UserDao;\nimport cn.abel.user.models.User;\nimport cn.abel.user.service.UserService;\nimport com.alibaba.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service(protocol = {\"dubbo\"}, validation = \"false\")\npublic class UserServiceImpl implements UserService {\n    @Autowired\n    private UserDao userDao;\n\n    @Override\n    public List<User> getByMap(Map<String, Object> map) {\n        return userDao.getByMap(map);\n    }\n\n    @Override\n    public User getById(Integer id) {\n        return userDao.getById(id);\n    }\n\n    @Override\n    public User create(User user) {\n        userDao.create(user);\n        return user;\n    }\n\n    @Override\n    public User update(User user) {\n        userDao.update(user);\n        return user;\n    }\n\n    @Override\n    public int delete(Integer id) {\n        return userDao.delete(id);\n    }\n\n    @Override\n    public User getByUserName(String userName) {\n        return userDao.getByUserName(userName);\n    }\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/java/cn/abel/user/utils/CommentUtils.java",
    "content": "package cn.abel.user.utils;\n\nimport com.alibaba.fastjson.JSON;\nimport org.apache.commons.collections4.CollectionUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2020/3/10\n */\npublic class CommentUtils {\n\n    /**\n     *\n     * @param list\n     * @param <T>\n     * @return\n     */\n    public static <T> List copyList(List<T> list) {\n        if (CollectionUtils.isEmpty(list)) {\n            return new ArrayList();\n        }\n        return JSON.parseArray(JSON.toJSONString(list), list.get(0).getClass());\n    }\n\n}\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/META-INF/spring/provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"${dubbo.application.name}\" owner=\"abel\" organization=\"abel\" logger=\"slf4j\"/>\n\n    <dubbo:registry protocol=\"zookeeper\" address=\"${dubbo.registry.address}\" file=\"false\" client=\"curator\"\n                    group=\"${dubbo.registry.group}\" version=\"${dubbo.registry.version}\"/>\n\n    <dubbo:annotation package=\"${dubbo.annotation.package}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"${dubbo.protocol.port}\" accesslog=\"${dubbo.log.file}\"/>\n\n    <!-- 指定服务使用rest协议并且暴露端口 -->\n    <dubbo:protocol name=\"rest\" port=\"${dubbo.protocol.rest.port}\" threads=\"500\" contextpath=\"\"\n                    server=\"tomcat\" accepts=\"500\" accesslog=\"${dubbo.log.file}\"\n                    extension=\"cn.abel.user.filter.RestFilter, cn.abel.user.filter.RestInterceptor, cn.abel.user.exception.RestExceptionMapper, cn.abel.user.exception.ServiceExceptionMapper, cn.abel.user.exception.ValidationExceptionMapper, cn.abel.user.exception.JsonExceptionMapper, cn.abel.user.exception.ReaderExceptionMapper,cn.abel.user.config.CustomParamConverterProvider\"/>\n\n    <dubbo:provider delay=\"-1\" timeout=\"5000\" threads=\"600\" threadpool=\"fixed\" loadbalance=\"roundrobin\" accesslog=\"true\"\n                    retries=\"0\" validation=\"true\"/>\n\n    <!--引用的外部服务。-->\n\n\n</beans>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/dev/application.properties",
    "content": "#application\nspring.application.name=abel-user-provider\napplication.main=cn.abel.user.UserProviderApplication\nserver.port=9658\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\nserver.tomcat.max-threads=200\nserver.session-timeout=60\nlog4j.logger.java.sql.Connection=DEBUG\n\n\n#dubbo\ndubbo.application.name=abel-user-provider\ndubbo.registry.group=abel\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.version=1.0.0\ndubbo.protocol.port=12885\ndubbo.protocol.rest.port=12886\ndubbo.annotation.package=cn.abel.user\ndubbo.log.file=/logs/abel-user-provider/abel-user-provider-dubbo.log\n\n#db\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiro?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\n#DataSource\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\nspring.datasource.hikari.minimum-idle=10\nspring.datasource.hikari.maximum-pool-size=30\nspring.datasource.hikari.idle-timeout=120000\nspring.datasource.hikari.max-lifetime=1800000\nspring.datasource.hikari.connection-timeout=30000\nspring.datasource.hikari.validation-timeout=3000\nspring.datasource.hikari.connection-test-query=SELECT 1\n\n\n#mybatis\nlogging.level.cn.abel.user.dao=info\nmybatis.type-aliases-package=cn.abel.user.model\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\n\n#PageHelper\npagehelper.helperDialect=mysql\npagehelper.reasonable=true\npagehelper.supportMethodsArguments=true\npagehelper.params=count=countSql\n\nlogging.file=/logs/abel-user-provider/abel-user-provider.log\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/dev/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        dev                           #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/dev/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>abel_user</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"INFO\"/>\n    <logger name=\"java.sql.Connection\" level=\"INFO\"/>\n    <logger name=\"java.sql.Statement\" level=\"INFO\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"INFO\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/local/application.properties",
    "content": "#application\nspring.application.name=abel-user-provider\napplication.main=cn.abel.user.UserProviderApplication\nserver.port=9658\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\nserver.tomcat.max-threads=200\nserver.session-timeout=60\nlog4j.logger.java.sql.Connection=DEBUG\n\n\n#dubbo\ndubbo.application.name=abel-user-provider\ndubbo.registry.group=abel\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.version=1.0.0\ndubbo.protocol.port=12885\ndubbo.protocol.rest.port=12886\ndubbo.annotation.package=cn.abel.user\ndubbo.log.file=./logs/abel-user-provider/abel-user-provider-dubbo.log\n\n#db\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiro?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\n#DataSource\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\nspring.datasource.hikari.minimum-idle=10\nspring.datasource.hikari.maximum-pool-size=30\nspring.datasource.hikari.idle-timeout=120000\nspring.datasource.hikari.max-lifetime=1800000\nspring.datasource.hikari.connection-timeout=30000\nspring.datasource.hikari.validation-timeout=3000\nspring.datasource.hikari.connection-test-query=SELECT 1\n\n\n#mybatis\nlogging.level.cn.abel.user.dao=info\nmybatis.type-aliases-package=cn.abel.user.model\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\n\n#PageHelper\npagehelper.helperDialect=mysql\npagehelper.reasonable=true\npagehelper.supportMethodsArguments=true\npagehelper.params=count=countSql\n\nlogging.file=./logs/abel-user-provider/abel-user-provider.log\n"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>abel_user</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"INFO\"/>\n    <logger name=\"java.sql.Connection\" level=\"INFO\"/>\n    <logger name=\"java.sql.Statement\" level=\"INFO\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"INFO\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/mapper/PermissionDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.abel.user.dao.PermissionDao\">\n    <resultMap id=\"permissionMap\" type=\"cn.abel.user.models.Permission\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"permissionUrl\" column=\"permission_url\"/>\n\t\t<result property=\"method\" column=\"method\"/>\n\t\t<result property=\"description\" column=\"description\"/>\n\n    </resultMap>\n\n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"permissionUrl != null and permissionUrl != ''\">\n\t\t\t\tand permission_url = #{permissionUrl}\n\t\t\t</if>\n\t\t\t<if test=\"method != null and method != ''\">\n\t\t\t\tand method = #{method}\n\t\t\t</if>\n\t\t\t<if test=\"description != null and description != ''\">\n\t\t\t\tand description = #{description}\n\t\t\t</if>\n\n        </where>\n    </sql>\n\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission\n\t\t<include refid=\"queryCondition\" />\n    </select>\n\n    <select id=\"getById\" parameterType=\"int\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission WHERE id =#{id}\n    </select>\n\n\t<select id=\"getList\"  resultMap=\"permissionMap\">\n\t\tSELECT * from permission\n\t</select>\n\n\t<select id=\"getByUserId\" parameterType=\"int\" resultMap=\"permissionMap\">\n\t\tselect p.*\n\t\tfrom user u\n\t\tLEFT JOIN user_role ur on u.id= ur.User_id\n\t\tLEFT JOIN role r on ur.role_id=r.id\n\t\tLEFT JOIN role_permission rp on rp.role_id=r.id\n\t\tLEFT JOIN permission p on p.id =rp.permission_id\n\t\twhere u.id=#{userId}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"cn.abel.user.models.Permission\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO permission(\n\t\t\tid,\n\t\t\tname,\n\t\t\tpermission_url,\n\t\t    method,\n\t\t\tdescription\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{permissionUrl},\n\t\t    #{method},\n\t\t\t#{description}\n\t\t)\n    </insert>\n\n    <update id=\"update\" parameterType=\"cn.abel.user.models.Permission\">\n\t\tUPDATE permission SET\n\t\t\tname = #{name},\n\t\t\tpermission_url = #{permissionUrl},\n\t\t\tmethod = #{method},\n\t\t\tdescription = #{description}\n\t\tWHERE id = #{id}\n    </update>\n\n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM permission WHERE id = #{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/mapper/RoleDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.user.dao.RoleDao\">\n    <resultMap id=\"roleMap\" type=\"cn.abel.user.models.Role\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"roleLevel\" column=\"role_level\"/>\n\t\t<result property=\"description\" column=\"description\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"roleLevel != null and roleLevel != ''\">\n\t\t\t\tand role_level = #{roleLevel}\n\t\t\t</if>\n\t\t\t<if test=\"description != null and description != ''\">\n\t\t\t\tand description = #{description}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"roleMap\">\n    \tSELECT * FROM role\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"roleMap\">\n    \tSELECT * FROM role WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.user.models.Role\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO role(\n\t\t\tid,\n\t\t\tname,\n\t\t\trole_level,\n\t\t\tdescription\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{roleLevel},\n\t\t\t#{description}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.user.models.Role\">\n\t\tUPDATE role SET\n\t\t\tname = #{name},\n\t\t\trole_level = #{roleLevel},\n\t\t\tdescription = #{description}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM role WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.user.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"cn.abel.user.models.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"cnname\" column=\"cnname\"/>\n\t\t<result property=\"username\" column=\"username\"/>\n\t\t<result property=\"password\" column=\"password\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"mobilePhone\" column=\"mobile_phone\"/>\n\t\t<collection property=\"roles\" ofType=\"cn.abel.user.models.Role\">\n\t\t\t<result column=\"name\" property=\"name\"/>\n\t\t</collection>\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"cnname != null and cnname != ''\">\n\t\t\t\tand cnname = #{cnname}\n\t\t\t</if>\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tand username = #{username}\n\t\t\t</if>\n\t\t\t<if test=\"password != null and password != ''\">\n\t\t\t\tand password = #{password}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"mobilePhone != null and mobilePhone != ''\">\n\t\t\t\tand mobile_phone = #{mobilePhone}\n\t\t\t</if>\n\t\t\t<if test=\"keywords != null and keywords != ''\">\n\t\t\t\tand (\n\t\t\t\t\tcnname like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR username like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR mobile_phone like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR email like CONCAT('%', #{keywords},'%')\n\t\t\t\t)\n\t\t\t</if>\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT * FROM user\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n\n\t<select id=\"getByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom user u\n\t\tLEFT JOIN user_role ur on u.id= ur.user_id\n\t\tLEFT JOIN role r on ur.role_id=r.id\n\t\twhere username= #{username}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"cn.abel.user.models.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tcnname,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\temail,\n\t\t\tmobile_phone\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{cnname},\n\t\t\t#{username},\n\t\t\t#{password},\n\t\t\t#{email},\n\t\t\t#{mobilePhone}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.user.models.User\">\n\t\tUPDATE user SET\n\t\t\tcnname = #{cnname},\n\t\t\tusername = #{username},\n\t\t\tpassword = #{password},\n\t\t\temail = #{email},\n\t\t\tmobile_phone = #{mobilePhone}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/test/cn/abel/user/BaseTest.java",
    "content": "package cn.abel.user;\n\n/**\n * @author yyb\n * @time 2020/3/9\n */\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = UserProviderApplication.class)\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest {\n\n    @Configuration\n    @ComponentScan(basePackages = {\"cn.abel.user\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n\n    @Test\n    public void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "springboot-dubbo/abel-user-provider/src/main/test/cn/abel/user/service/impl/PermissionServiceImplTest.java",
    "content": "package cn.abel.user.service.impl;\n\nimport cn.abel.user.BaseTest;\nimport cn.abel.user.models.Permission;\nimport cn.abel.user.service.PermissionService;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport static org.junit.Assert.*;\n\n/**\n * @author yyb\n * @time 2020/3/20\n */\npublic class PermissionServiceImplTest extends BaseTest {\n    @Autowired\n    private PermissionService permissionService;\n    @Test\n    public void getByMap() throws Exception {\n        permissionService.getByMap(null);\n    }\n\n    @Test\n    public void getById() throws Exception {\n        Permission permission = permissionService.getById(1);\n        System.out.println();\n    }\n\n    @Test\n    public void create() throws Exception {\n        Permission permission = new Permission();\n        permission.setDescription(\"234234\");\n        permission.setName(\"新增\");\n        permission.setMethod(\"nicai\");\n        permission.setPermissionUrl(\"zsdfsf_sf\");\n        permissionService.create(permission);\n    }\n\n    @Test\n    public void update() throws Exception {\n        Permission permission = new Permission();\n        permission.setId(1);\n        permission.setDescription(\"234234\");\n        permission.setName(\"新增\");\n        permission.setMethod(\"nicai\");\n        permission.setPermissionUrl(\"zsdfsf_sf\");\n        permissionService.update(permission);\n    }\n\n    @Test\n    public void delete() throws Exception {\n        permissionService.delete(1);\n    }\n\n}"
  },
  {
    "path": "springboot-dynamicDataSource/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-dynamicDataSource</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.40</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-dynamicDataSource/sql/news.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50719\n Source Host           : 127.0.0.1\n Source Database       : oldMan\n\n Target Server Type    : MySQL\n Target Server Version : 50719\n File Encoding         : utf-8\n\n Date: 04/02/2019 15:38:58 PM\n*/\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n--  Table structure for `news`\n-- ----------------------------\nDROP TABLE IF EXISTS `news`;\nCREATE TABLE `news` (\n  `id` int(11) NOT NULL,\n  `title` varchar(100) DEFAULT NULL,\n  `content` text,\n  `image_path` varchar(100) DEFAULT NULL,\n  `read_sum` int(11) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "springboot-dynamicDataSource/sql/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50719\n Source Host           : 127.0.0.1\n Source Database       : oldMan\n\n Target Server Type    : MySQL\n Target Server Version : 50719\n File Encoding         : utf-8\n\n Date: 04/02/2019 15:27:32 PM\n*/\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n--  Table structure for `user`\n-- ----------------------------\nDROP TABLE IF EXISTS `user`;\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` varchar(100) DEFAULT NULL,\n  `address` varchar(200) DEFAULT NULL,\n  `mobile` varchar(50) DEFAULT NULL,\n  `email` varchar(100) DEFAULT NULL,\n  `create_time` datetime DEFAULT NULL,\n  `role` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/Application.java",
    "content": "package cn.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/3/26\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/bean/News.java",
    "content": "package cn.abel.bean;\n\n\npublic class News {\n    private Integer id;\n    private String title;\n    private String content;\n    private String imagePath;\n    private Integer readSum;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getImagePath() {\n        return imagePath;\n    }\n\n    public void setImagePath(String imagePath) {\n        this.imagePath = imagePath;\n    }\n\n    public Integer getReadSum() {\n        return readSum;\n    }\n\n    public void setReadSum(Integer readSum) {\n        this.readSum = readSum;\n    }\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/bean/User.java",
    "content": "package cn.abel.bean;\n\nimport java.util.Date;\n\n\npublic class User {\n    private Integer id;\n    private String name;\n    private String address;\n    private String mobile;\n    private String email;\n    private Date createTime;\n    private Integer role;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public Integer getRole() {\n        return role;\n    }\n\n    public void setRole(Integer role) {\n        this.role = role;\n    }\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/config/DynamicDataSource.java",
    "content": "package cn.abel.config;\n\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic class DynamicDataSource extends AbstractRoutingDataSource {\n    @Override\n    protected Object determineCurrentLookupKey() {\n        return DynamicDataSourceContextHolder.getDatabaseType();\n    }\n}\n\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/config/DynamicDataSourceConfig.java",
    "content": "package cn.abel.config;\n\nimport cn.abel.enums.DatabaseTypeEnum;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\nimport javax.sql.DataSource;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@Configuration\n@MapperScan(basePackages = \"cn.abel.dao\")\npublic class DynamicDataSourceConfig {\n    @Value(\"${spring.datasource.primary.url}\")\n    private String primaryUrl;\n    @Value(\"${spring.datasource.user.url}\")\n    private String userUrl;\n    @Value(\"${mybatis.mapper-locations}\")\n    private String resources;\n    //当两个数据库连接账号密码不一样时\n//    @Value(\"${spring.datasource.user.username}\")\n//    private String userName;\n//    @Value(\"${spring.datasource.user.password}\")\n//    private String password;\n\n    @Autowired\n    private HikariConfig hikariConfig;\n\n    @Primary\n    @Bean(name = \"primaryDataSource\")\n    public DataSource getPrimaryDataSource() {\n        return hikariConfig.getHikariDataSource(primaryUrl);\n    }\n\n    @Bean(name = \"userDataSource\")\n    public DataSource getUserDataSource() {\n        return hikariConfig.getHikariDataSource(userUrl);\n    }\n\n\n    //当两个数据库连接账号密码不一样时使用\n//    @Bean(name = \"userDataSource\")\n//    public DataSource getUserDataSource() {\n//        return hikariConfig.getHikariDataSource(userUrl, userName, password);\n//    }\n\n\n    @Bean(\"dynamicDataSource\")\n    public DynamicDataSource dynamicDataSource(@Qualifier(\"primaryDataSource\") DataSource primaryDataSource,\n                                               @Qualifier(\"userDataSource\") DataSource userDataSource) {\n        Map<Object, Object> targetDataSources = new HashMap<>();\n        targetDataSources.put(DatabaseTypeEnum.PRIMARY, primaryDataSource);\n        targetDataSources.put(DatabaseTypeEnum.USER, userDataSource);\n\n        DynamicDataSource dataSource = new DynamicDataSource();\n        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法\n        dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认的datasource设置为myTestDbDataSource\n        return dataSource;\n    }\n\n    /**\n     * 根据数据源创建SqlSessionFactory\n     */\n    @Bean\n    public SqlSessionFactory sqlSessionFactory(@Qualifier(\"dynamicDataSource\") DynamicDataSource dynamicDataSource) throws Exception {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dynamicDataSource);\n        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(resources));\n        return bean.getObject();\n    }\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/config/DynamicDataSourceContextHolder.java",
    "content": "package cn.abel.config;\n\nimport cn.abel.enums.DatabaseTypeEnum;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic class DynamicDataSourceContextHolder {\n    private static final ThreadLocal<DatabaseTypeEnum> contextHolder = new ThreadLocal<>();\n\n    public static void setDatabaseType(DatabaseTypeEnum type){\n        contextHolder.set(type);\n    }\n\n    public static DatabaseTypeEnum getDatabaseType(){\n        return contextHolder.get();\n    }\n\n    public static void resetDatabaseType() {\n        contextHolder.set(DatabaseTypeEnum.PRIMARY);\n    }\n}\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/config/HikariConfig.java",
    "content": "package cn.abel.config;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@Service\npublic class HikariConfig {\n    @Value(\"${spring.datasource.username}\")\n    private String userName;\n    @Value(\"${spring.datasource.password}\")\n    private String password;\n    @Value(\"${spring.datasource.driver-class-name}\")\n    private String driverClassName;\n    @Value(\"${spring.datasource.min-idle}\")\n    private Integer minIdle;\n    @Value(\"${spring.datasource.max-active}\")\n    private Integer maxActive;\n    @Value(\"${spring.datasource.validation-query}\")\n    private String validationQuery;\n    @Value(\"${spring.datasource.connection-timeout}\")\n    private Integer connectionTimeout;\n    @Value(\"${spring.datasource.max-left-time}\")\n    private Integer maxLeftTime;\n    @Value(\"${spring.datasource.validation-time-out}\")\n    private Integer validationTimeout;\n    @Value(\"${spring.datasource.idle-time-out}\")\n    private Integer idleTimeout;\n    @Value(\"${spring.datasource.connection-init-sql}\")\n    private String connectionInitSql;\n\n    /**\n     * 配置Hikari数据连接池\n     *\n     * @param url 数据源\n     * @return 连接池对象\n     */\n    public HikariDataSource getHikariDataSource(String url) {\n        com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();\n        config.setMinimumIdle(minIdle);\n        config.setMaximumPoolSize(maxActive);\n        config.setConnectionTestQuery(validationQuery);\n        config.setJdbcUrl(url);\n        config.setUsername(userName);\n        config.setPassword(password);\n        config.setDriverClassName(driverClassName);\n        config.setConnectionTimeout(connectionTimeout);\n        config.setMaxLifetime(maxLeftTime);\n        config.setValidationTimeout(validationTimeout);\n        config.setConnectionInitSql(connectionInitSql);\n        return new HikariDataSource(config);\n    }\n\n    /**\n     * 用于两个库账号密码不一样的时候\n     *\n     * @param url\n     * @param userName\n     * @param passwod\n     * @return\n     */\n    public HikariDataSource getHikariDataSource(String url, String userName, String passwod) {\n        com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();\n        config.setMinimumIdle(minIdle);\n        config.setMaximumPoolSize(maxActive);\n        config.setConnectionTestQuery(validationQuery);\n        config.setJdbcUrl(url);\n        config.setUsername(userName);\n        config.setPassword(passwod);\n        config.setConnectionTimeout(connectionTimeout);\n        config.setDriverClassName(driverClassName);\n        config.setMaxLifetime(maxLeftTime);\n        config.setValidationTimeout(validationTimeout);\n        config.setConnectionInitSql(connectionInitSql);\n        return new HikariDataSource(config);\n    }\n}\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/dao/NewsDao.java",
    "content": "package cn.abel.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.bean.News;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\n@Repository\n@Mapper\npublic interface NewsDao {\n\n    List<News> getByMap(Map<String, Object> map);\n\n    News getById(Integer id);\n\n    Integer create(News news);\n\n    int update(News news);\n\n    int delete(Integer id);\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/dao/UserDao.java",
    "content": "package cn.abel.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.bean.User;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\n@Repository\n@Mapper\npublic interface UserDao {\n\n    List<User> getByMap(Map<String, Object> map);\n\n    User getById(Integer id);\n\n    Integer create(User user);\n\n    int update(User user);\n\n    int delete(Integer id);\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/enums/DatabaseTypeEnum.java",
    "content": "package cn.abel.enums;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic enum DatabaseTypeEnum {\n    PRIMARY(\"1\"), USER(\"2\");\n\n    private String code;\n\n    DatabaseTypeEnum(String code) {\n        this.code = code;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public void setCode(String code) {\n        this.code = code;\n    }\n\n    public static DatabaseTypeEnum getDatabaseTypeEnum(String code) {\n        for (DatabaseTypeEnum databaseTypeEnum : DatabaseTypeEnum.values()) {\n            if (databaseTypeEnum.getCode().equals(code)) {\n                return databaseTypeEnum;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/service/NewsService.java",
    "content": "package cn.abel.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.config.DynamicDataSource;\nimport cn.abel.config.DynamicDataSourceContextHolder;\nimport cn.abel.enums.DatabaseTypeEnum;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport cn.abel.dao.NewsDao;\nimport cn.abel.bean.News;\n\n@Service\npublic class NewsService {\n    @Autowired\n    private NewsDao newsDao;\n\n    public List<News> getByMap(Map<String, Object> map) {\n        DynamicDataSourceContextHolder.resetDatabaseType();\n        return newsDao.getByMap(map);\n    }\n\n    public News getById(Integer id) {\n        DynamicDataSourceContextHolder.resetDatabaseType();\n        return newsDao.getById(id);\n    }\n\n    public News create(News news) {\n        DynamicDataSourceContextHolder.resetDatabaseType();\n        newsDao.create(news);\n        return news;\n    }\n\n    public News update(News news) {\n        DynamicDataSourceContextHolder.resetDatabaseType();\n        newsDao.update(news);\n        return news;\n    }\n\n    public int delete(Integer id) {\n        DynamicDataSourceContextHolder.resetDatabaseType();\n        return newsDao.delete(id);\n    }\n\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/java/cn/abel/service/UserService.java",
    "content": "package cn.abel.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.config.DynamicDataSourceContextHolder;\nimport cn.abel.enums.DatabaseTypeEnum;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport cn.abel.dao.UserDao;\nimport cn.abel.bean.User;\n\n@Service\npublic class UserService {\n    @Autowired\n\tprivate UserDao userDao;\n\t\n\tpublic List<User> getByMap(Map<String,Object> map){\n\t\tDynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);\n\t\treturn userDao.getByMap(map);\n\t}\n\t\n\tpublic User getById(Integer id){\n\t\tDynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);\n\t\treturn userDao.getById(id);\n\t}\n\t\n\tpublic User create(User user){\n\t\tDynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);\n\t\tuserDao.create(user);\n\t\treturn user;\n\t}\n\t\n\tpublic User update(User user){\n\t\tDynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);\n\t\tuserDao.update(user);\n\t\treturn user;\n\t}\n\t\n\tpublic int delete(Integer id){\n\t\tDynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);\n\t\treturn userDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=8009\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.abel.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200  \nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-dynamicDataSource\napplication.main=cn.abel.Application\n\n## LOG\nlogging.file=./logs/springboot-dynamicDataSource.log\n\n\n## \\u4E3B\\u6570\\u636E\\u6E90\\uFF0C\\u9ED8\\u8BA4\\u7684\nspring.datasource.primary.url=jdbc:mysql://localhost:3306/oldMan?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.user.url=jdbc:mysql://localhost:3306/rules?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\n\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\n#\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.datasource.min-idle=5\n#\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\u91CF\nspring.datasource.max-active=100\n#\\u68C0\\u6D4B\\u6570\\u636E\\u5E93\\u7684\\u67E5\\u8BE2\\u8BED\\u53E5\nspring.datasource.validation-query=select 1 from dual\n#\\u7B49\\u5F85\\u8FDE\\u63A5\\u6C60\\u5206\\u914D\\u8FDE\\u63A5\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.connection-timeout=60000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5\\u7684\\u751F\\u547D\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.max-left-time=60000\n#\\u751F\\u6548\\u8D85\\u65F6\nspring.datasource.validation-time-out=3000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5idle\\u72B6\\u6001\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.idle-time-out=60000\n#\\u8BBE\\u7F6E\\u9ED8\\u8BA4\\u5B57\\u7B26\\u96C6\nspring.datasource.connection-init-sql= set names utf8mb4\n\nlogging.level.cn.abel.dao=debug\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\nsmybatis.type-aliases-package=cn.abel.bean\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\n\n## pagehelper\npagehelper.helperDialect=mysql\npagehelper.reasonable=true\npagehelper.supportMethodsArguments=true\npagehelper.params=count=countSql\n\n\n"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-dataSource</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/resources/mapper/NewsDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.dao.NewsDao\">\n    <resultMap id=\"newsMap\" type=\"cn.abel.bean.News\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"title\" column=\"title\"/>\n\t\t<result property=\"content\" column=\"content\"/>\n\t\t<result property=\"imagePath\" column=\"image_path\"/>\n\t\t<result property=\"readSum\" column=\"read_sum\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"title != null and title != ''\">\n\t\t\t\tand title = #{title}\n\t\t\t</if>\n\t\t\t<if test=\"content != null and content != ''\">\n\t\t\t\tand content = #{content}\n\t\t\t</if>\n\t\t\t<if test=\"imagePath != null and imagePath != ''\">\n\t\t\t\tand image_path = #{imagePath}\n\t\t\t</if>\n\t\t\t<if test=\"readSum != null and readSum != ''\">\n\t\t\t\tand read_sum = #{readSum}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"newsMap\">\n    \tSELECT * FROM news\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"newsMap\">\n    \tSELECT * FROM news WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.bean.News\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO news(\n\t\t\tid,\n\t\t\ttitle,\n\t\t\tcontent,\n\t\t\timage_path,\n\t\t\tread_sum\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{title},\n\t\t\t#{content},\n\t\t\t#{imagePath},\n\t\t\t#{readSum}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.bean.News\">\n\t\tUPDATE news SET\n\t\t\ttitle = #{title},\n\t\t\tcontent = #{content},\n\t\t\timage_path = #{imagePath},\n\t\t\tread_sum = #{readSum}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM news WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-dynamicDataSource/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"cn.abel.bean.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"address\" column=\"address\"/>\n\t\t<result property=\"mobile\" column=\"mobile\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"createTime\" column=\"create_time\"/>\n\t\t<result property=\"role\" column=\"role\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"address != null and address != ''\">\n\t\t\t\tand address = #{address}\n\t\t\t</if>\n\t\t\t<if test=\"mobile != null and mobile != ''\">\n\t\t\t\tand mobile = #{mobile}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"role != null and role != ''\">\n\t\t\t\tand role = #{role}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT * FROM user\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.bean.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tname,\n\t\t\taddress,\n\t\t\tmobile,\n\t\t\temail,\n\t\t\tcreate_time,\n\t\t\trole\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{address},\n\t\t\t#{mobile},\n\t\t\t#{email},\n\t\t\tNOW(),\n\t\t\t#{role}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.bean.User\">\n\t\tUPDATE user SET\n\t\t\tname = #{name},\n\t\t\taddress = #{address},\n\t\t\tmobile = #{mobile},\n\t\t\temail = #{email},\n\t\t\trole = #{role}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-dynamicDataSource/src/test/java/cn/abel/BaseTest.java",
    "content": "package cn.abel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest {\n\n    @Configuration\n    @ComponentScan(basePackages = {\"cn.abel\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n\n    @Test\n    public void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "springboot-dynamicDataSource/src/test/java/cn/abel/service/ServiceTest.java",
    "content": "package cn.abel.service;\n\nimport cn.abel.BaseTest;\nimport cn.abel.bean.News;\nimport cn.abel.bean.User;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic class ServiceTest extends BaseTest {\n\n    @Autowired\n    private NewsService newsService;\n    @Autowired\n    private UserService userService;\n\n    @Test\n    public void dynamicDataSourceTest() throws Exception {\n        List<News> newsList = newsService.getByMap(null);\n        List<User> userList = userService.getByMap(null);\n        System.out.println(\"newsList----\" + newsList.size() + \"--userList---\" + userList.size());\n\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/README.md",
    "content": "\n## springboot-elasticsearch\n \n* 本项目是speingboot结合es 的小李子。\n* 演示了同一个项目配置多个es 数据源\n* es操作是用es的rest api 进行操作，操作语句是 通过 JSONObject 对象进行拼接，可以执行增、删、改、查 行为。\n具体的操作命令可以查看 Es RESTful API 官方文档\n\nhttps://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html"
  },
  {
    "path": "springboot-elasticsearch/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-elasticserach</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.40</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n        <!--es-->\n\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-client</artifactId>\n            <version>6.8.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.40</version>\n        </dependency>\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/Application.java",
    "content": "package cn.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/3/26\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/bean/User.java",
    "content": "package cn.abel.bean;\n\nimport java.util.Date;\n\n\npublic class User {\n    private Integer id;\n    private String name;\n    private String address;\n    private String mobile;\n    private String email;\n    private Date createTime;\n    private Integer role;\n    private String idCard;\n    private int type;\n\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public Integer getRole() {\n        return role;\n    }\n\n    public void setRole(Integer role) {\n        this.role = role;\n    }\n\n    public String getIdCard() {\n        return idCard;\n    }\n\n    public void setIdCard(String idCard) {\n        this.idCard = idCard;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n}"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/config/ESRestClient2Config.java",
    "content": "package cn.abel.config;\n\nimport org.apache.http.HttpHost;\nimport org.apache.http.auth.AuthScope;\nimport org.apache.http.auth.UsernamePasswordCredentials;\nimport org.apache.http.client.CredentialsProvider;\nimport org.apache.http.impl.client.BasicCredentialsProvider;\nimport org.apache.http.impl.nio.client.HttpAsyncClientBuilder;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 第二数据源\n * @author yyb\n * @time 2020/4/2\n */\n@Configuration\npublic class ESRestClient2Config {\n    public static final String NAME = \"ESRestClient2Config\";\n\n    @Value(\"${elasticsearch2.userName}\")\n    private String userName;\n    @Value(\"${elasticsearch2.password}\")\n    private String password;\n    @Value(\"${elasticsearch2.rest.hostNames}\")\n    private String hostName;\n    @Value(\"${elasticsearch2.rest.port}\")\n    private Integer port;\n\n    @Bean(name = NAME, destroyMethod = \"close\")\n    public RestClient getRestClient() {\n        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n        credentialsProvider.setCredentials(AuthScope.ANY,\n                new UsernamePasswordCredentials(userName, password));\n        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(hostName, port));\n        //配置身份验证\n        restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {\n            @Override\n            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {\n                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);\n            }\n        });\n        return restClientBuilder.build();\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/config/ESRestClientConfig.java",
    "content": "package cn.abel.config;\n\nimport org.apache.http.HttpHost;\nimport org.apache.http.auth.AuthScope;\nimport org.apache.http.auth.UsernamePasswordCredentials;\nimport org.apache.http.client.CredentialsProvider;\nimport org.apache.http.impl.client.BasicCredentialsProvider;\nimport org.apache.http.impl.nio.client.HttpAsyncClientBuilder;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 第一数据源\n * @author yangyibo\n * @time 2019/4/2\n */\n@Configuration\npublic class ESRestClientConfig {\n    public static final String NAME = \"ESRestClientConfig\";\n\n    @Value(\"${elasticsearch.userName}\")\n    private String userName;\n    @Value(\"${elasticsearch.password}\")\n    private String password;\n    @Value(\"${elasticsearch.rest.hostNames}\")\n    private String hostName;\n    @Value(\"${elasticsearch.rest.port}\")\n    private Integer port;\n\n    @Bean(name = NAME, destroyMethod = \"close\")\n    public RestClient getRestClient() {\n        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n        credentialsProvider.setCredentials(AuthScope.ANY,\n                new UsernamePasswordCredentials(userName, password));\n        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(hostName, port));\n        //配置身份验证\n        restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {\n            @Override\n            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {\n                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);\n            }\n        });\n        return restClientBuilder.build();\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/constants/Constants.java",
    "content": "package cn.abel.constants;\n\n/**\n * @author yangyibo\n * @time 2019/4/3\n */\npublic class Constants {\n\n    /**\n     * es 查询query 拼接 前缀\n     */\n    public static final String ES_QUERY_JSON_PREFIX = \"{\\n\" +\n            \"  \\\"query\\\": {\\n\" +\n            \"    \\\"term\\\": {\\n\" +\n            \"      \\\"userId\\\": {\\n\" +\n            \"        \\\"value\\\": \\\"\";\n    /**\n     * es 查询query 拼接后缀\n     */\n    public static final String ES_QUERY_JSON_SUFFIX = \"\\\"\\n\" +\n            \"      }\\n\" +\n            \"    }\\n\" +\n            \"  }\\n\" +\n            \"}\\n\";\n\n    /**\n     * 需要查询的es的 index\n     */\n    public static final String ES_INDEX_PATH = \"/logstash_indes/_search\";\n\n}\n\n\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/dao/UserDao.java",
    "content": "package cn.abel.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.bean.User;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\n@Repository\n@Mapper\npublic interface UserDao {\n\n    List<User> getByMap(Map<String, Object> map);\n\n    User getById(Integer id);\n\n    Integer create(User user);\n\n    int update(User user);\n\n    int delete(Integer id);\n}"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/cn/abel/service/UserService.java",
    "content": "package cn.abel.service;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.elasticsearch.client.Request;\nimport org.elasticsearch.client.Response;\nimport org.elasticsearch.client.RestClient;\nimport cn.abel.config.ESRestClient2Config;\nimport cn.abel.config.ESRestClientConfig;\nimport cn.abel.constants.Constants;\nimport com.alibaba.fastjson.JSONArray;\nimport com.alibaba.fastjson.JSONObject;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.node.ArrayNode;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.nio.entity.NStringEntity;\nimport org.apache.http.util.EntityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.stereotype.Service;\n\nimport cn.abel.dao.UserDao;\nimport cn.abel.bean.User;\n\n/**\n * @author yyb\n */\n@Service\npublic class UserService {\n    private static final Logger logger = LoggerFactory.getLogger(UserService.class);\n    protected static final ObjectMapper mapper = new ObjectMapper();\n\n    @Autowired\n    private UserDao userDao;\n\n    /**\n     * 数据源1\n     */\n    @Autowired\n    @Qualifier(ESRestClientConfig.NAME)\n    private RestClient restClient;\n\n    /**\n     * 数据源2\n     */\n    @Autowired\n    @Qualifier(ESRestClient2Config.NAME)\n    private RestClient restClient2;\n\n\n    public List<User> getByMap(Map<String, Object> map) {\n        return userDao.getByMap(map);\n    }\n\n    public User getById(Integer id) throws Exception {\n        //拼接es 的查询query\n        String json = Constants.ES_QUERY_JSON_PREFIX + id + Constants.ES_QUERY_JSON_SUFFIX;\n        HttpEntity entry = new NStringEntity(json, ContentType.APPLICATION_JSON);\n        Response response = restClient.performRequest(HttpGet.METHOD_NAME, Constants.ES_INDEX_PATH, Collections.emptyMap(), entry);\n        JSONObject responseJson = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));\n        //es 中查询的结果\n        System.out.println(responseJson);\n        return userDao.getById(id);\n    }\n\n\n    /**\n     * 查询用户列表\n     *\n     * @param keyword   关键字用户名字/用户手机号/用户身份证号\n     * @param type      用户类型/1：注册用户/2：转化用户\n     * @param startTime 时间范围 起始时间\n     * @param endTime   时间范围 结束时间\n     * @param pageSize\n     * @param pageIndex\n     * @return\n     * @throws Exception\n     */\n    public JSONObject getList(String keyword, Integer type, String startTime, String endTime, int pageSize, int pageIndex) throws Exception {\n        JsonNode searchResponse;\n        JSONObject response = new JSONObject();\n        JSONObject search = searchListQuery(keyword, type, startTime, endTime, pageSize, pageIndex);\n        //根据档案英文名切换不同的索引\n        String endpoint = \"/user_Info_index/user/_search\";\n\n        searchResponse = esSearch(search, endpoint, restClient);\n        if (null == searchResponse) {\n            return response;\n        }\n        JsonNode hitsNode = searchResponse.get(\"hits\");\n        ArrayNode hitsArray = (ArrayNode) hitsNode.get(\"hits\");\n        response.put(\"total\", hitsNode.get(\"total\").intValue());\n        JSONArray list = new JSONArray();\n        for (JsonNode hit : hitsArray) {\n            JSONObject result = (JSONObject) JSONObject.parse(hit.get(\"_source\").toString());\n            list.add(result);\n        }\n        response.put(\"list\", list);\n        return response;\n    }\n\n\n    public User create(User user) {\n        userDao.create(user);\n        return user;\n    }\n\n    public User update(User user) {\n        userDao.update(user);\n        return user;\n    }\n\n    public int delete(Integer id) {\n        return userDao.delete(id);\n    }\n\n\n    /**\n     * 拼装列表查询query\n     *\n     * @param keyword\n     * @return\n     */\n    private JSONObject searchListQuery(String keyword, Integer type, String startTime, String endTime, int pageSize, int pageIndex) {\n        //只返回列表所需数据\n        String[] source = new String[]{\"id\", \"user_name\", \"id_card\", \"user_name\", \"mobile\", \"type\", \"create_time\"};\n        JSONObject search = new JSONObject();\n        search.put(\"_source\", source);\n        if (pageIndex <= 0) {\n            pageIndex = 1;\n        }\n        JSONObject bool = new JSONObject();\n        JSONArray sort = new JSONArray();\n\n        //查询类型\n        JSONArray mustArray = new JSONArray();\n        if (null != type) {\n            mustArray.add(getJSONObject(\"term\", getJSONObject(\"type\", type)));\n        }\n        bool.put(\"must\", mustArray);\n\n        //关键字查询\n        if (StringUtils.isNotEmpty(keyword)) {\n            JSONObject multiMatch = new JSONObject();\n            multiMatch.put(\"query\", keyword);\n            multiMatch.put(\"fields\", new String[]{\"user_name.keyword\", \"user_name\"});\n            //查询条件\n            JSONArray shouldArray = new JSONArray();\n            //虚化查询\n            shouldArray.add(getJSONObject(\"term\", getJSONObject(\"id_card\", keyword)));\n            shouldArray.add(getJSONObject(\"term\", getJSONObject(\"mobile\", keyword)));\n            shouldArray.add(getJSONObject(\"multi_match\", multiMatch));\n            //关键字评分排序\n            sort.add(getJSONObject(\"_score\", getJSONObject(\"order\", \"desc\")));\n            //should 必须命中一个\n            bool.put(\"minimum_should_match\", 1);\n            bool.put(\"should\", shouldArray);\n        }\n\n        //排序和时间过滤\n        JSONObject rangeField = new JSONObject();\n        //筛选创建时间大于 startTime 小于  endTime 的数据\n        rangeField.put(\"gte\", startTime);\n        rangeField.put(\"lte\", endTime);\n        JSONObject range = new JSONObject();\n        range.put(\"range\", getJSONObject(\"create_time\", rangeField));\n        //按照创建时间规则倒叙排序\n        sort.add(getJSONObject(\"create_time\", getJSONObject(\"order\", \"desc\")));\n        bool.put(\"filter\", range);\n\n        search.put(\"sort\", sort);\n        search.put(\"query\", getJSONObject(\"bool\", bool));\n        return setPage(pageIndex, pageSize, search);\n    }\n\n\n    /**\n     * ES查询\n     *\n     * @param search\n     * @return\n     */\n    public JsonNode esSearch(JSONObject search, String endpoint, RestClient restClient) {\n        JsonNode responseNode = null;\n        try {\n            logger.info(\"查询es语句为 {}, endpoint 为：{}\", search, endpoint.toString());\n\n            Request request = new Request(HttpGet.METHOD_NAME, endpoint);\n            if (search != null) {\n                String data = search.toString();\n                request.setJsonEntity(data);\n            }\n            try {\n                restClient.performRequest(request);\n            } catch (IOException e) {\n                logger.error(\"查询es语句报错为 {}\", e.getMessage());\n            }\n            Response response = restClient.performRequest(request);\n            String responseStr = EntityUtils.toString(response.getEntity());\n            logger.info(\"查询结果为\", responseStr);\n            responseNode = mapper.readTree(responseStr);\n        } catch (IOException e) {\n            logger.error(\"查询失败\", e);\n        }\n        return responseNode;\n    }\n\n\n    /**\n     * 设置页面\n     *\n     * @param pageIndex\n     * @param pageSize\n     * @param search\n     * @return\n     */\n    public static JSONObject setPage(Integer pageIndex, Integer pageSize, JSONObject search) {\n        search.put(\"from\", (pageIndex - 1) * pageSize);\n        search.put(\"size\", pageSize);\n        return search;\n    }\n\n\n    /**\n     * 获取json 对象\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    public static JSONObject getJSONObject(String key, Object value) {\n        JSONObject term = new JSONObject();\n        term.put(key, value);\n        return term;\n    }\n}"
  },
  {
    "path": "springboot-elasticsearch/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=8009\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.es.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200  \nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-elasticsearch\napplication.main=cn.abel.Application\n\n## LOG\nlogging.file=./logs/springboot-elasticsearch.log\n\n\n## \\u4E3B\\u6570\\u636E\\u6E90\\uFF0C\\u9ED8\\u8BA4\\u7684\nspring.datasource.url=jdbc:mysql://localhost:3306/oldMan?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\n\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\n#\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.datasource.min-idle=5\n#\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\u91CF\nspring.datasource.max-active=100\n#\\u68C0\\u6D4B\\u6570\\u636E\\u5E93\\u7684\\u67E5\\u8BE2\\u8BED\\u53E5\nspring.datasource.validation-query=select 1 from dual\n#\\u7B49\\u5F85\\u8FDE\\u63A5\\u6C60\\u5206\\u914D\\u8FDE\\u63A5\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.connection-timeout=60000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5\\u7684\\u751F\\u547D\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.max-left-time=60000\n#\\u751F\\u6548\\u8D85\\u65F6\nspring.datasource.validation-time-out=3000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5idle\\u72B6\\u6001\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.idle-time-out=60000\n#\\u8BBE\\u7F6E\\u9ED8\\u8BA4\\u5B57\\u7B26\\u96C6\nspring.datasource.connection-init-sql= set names utf8mb4\n\nlogging.level.cn.abel.dao=debug\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\nsmybatis.type-aliases-package=cn.abel.bean\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\n\n## pagehelper\npagehelper.helperDialect=mysql\npagehelper.reasonable=true\npagehelper.supportMethodsArguments=true\npagehelper.params=count=countSql\n\n#es\\u670D\\u52A1\\u5668\\u5730\\u5740\\u914D\\u7F6E\nelasticsearch.userName=\nelasticsearch.password=\nelasticsearch.rest.hostNames=127.0.0.1\nelasticsearch.rest.port=9200\n\n\n#es2\\u670D\\u52A1\\u5668\\u5730\\u5740\\u914D\\u7F6E\nelasticsearch2.userName=\nelasticsearch2.password=\nelasticsearch2.rest.hostNames=127.0.0.1\nelasticsearch2.rest.port=9200"
  },
  {
    "path": "springboot-elasticsearch/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-elasticsearch/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-es</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-elasticsearch/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"cn.abel.bean.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"address\" column=\"address\"/>\n\t\t<result property=\"mobile\" column=\"mobile\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"createTime\" column=\"create_time\"/>\n\t\t<result property=\"role\" column=\"role\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"address != null and address != ''\">\n\t\t\t\tand address = #{address}\n\t\t\t</if>\n\t\t\t<if test=\"mobile != null and mobile != ''\">\n\t\t\t\tand mobile = #{mobile}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"role != null and role != ''\">\n\t\t\t\tand role = #{role}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT * FROM user\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.bean.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tname,\n\t\t\taddress,\n\t\t\tmobile,\n\t\t\temail,\n\t\t\tcreate_time,\n\t\t\trole\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{address},\n\t\t\t#{mobile},\n\t\t\t#{email},\n\t\t\tNOW(),\n\t\t\t#{role}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.bean.User\">\n\t\tUPDATE user SET\n\t\t\tname = #{name},\n\t\t\taddress = #{address},\n\t\t\tmobile = #{mobile},\n\t\t\temail = #{email},\n\t\t\trole = #{role}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-elasticsearch/src/test/java/cn/abel/BaseTest.java",
    "content": "package cn.abel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest {\n\n    @Configuration\n    @ComponentScan(basePackages = {\"cn.abel\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n\n    @Test\n    public void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "springboot-elasticsearch/src/test/java/cn/abel/service/ServiceTest.java",
    "content": "package cn.abel.service;\n\nimport cn.abel.BaseTest;\nimport cn.abel.bean.User;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic class ServiceTest extends BaseTest {\n\n\n    @Autowired\n    private UserService userService;\n\n    @Test\n    public void dynamicDataSourceTest() throws Exception {\n        User user = userService.getById(1);\n        System.out.println(\"--userList---\" + user.toString());\n\n    }\n}\n"
  },
  {
    "path": "springboot-jpa/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-jpa</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n    <!-- springboot -->\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--util-->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/bean/User.java",
    "content": "package com.us.example.bean;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\n@Entity\n@Table(name = \"sec_user\")\npublic class User {\n    @Id\n    @GeneratedValue\n    private Integer id;\n    @Column(name = \"name\")\n    private String name;\n    @Column(name = \"password\")\n    private String password;\n    @Column(name = \"username\")\n    private String username;\n    @Column(name = \"division_id\")\n    private Integer divisionId;\n    @Column(name = \"email\")\n    private String email;\n    @Column(name = \"gender\")\n    private String gender;\n    @Column(name = \"mobilephone\")\n    private String mobilephone;\n    @Column(name = \"telephone\")\n    private String telephone;\n    @Column(name = \"user_type\")\n    private Integer userType;\n    @Column(name = \"create_by\")\n    private String createBy;\n    @Column(name = \"create_time\")\n    private Date createTime;\n    @Column(name = \"update_by\")\n    private String updateBy;\n    @Column(name = \"update_time\")\n    private Date updateTime;\n    @Column(name = \"disabled\")\n    private Integer disabled;\n    @Column(name = \"theme\")\n    private String theme;\n    @Column(name = \"is_ldap\")\n    private Integer isLdap;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @JsonIgnore\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public Integer getDivisionId() {\n        return divisionId;\n    }\n\n    public void setDivisionId(Integer divisionId) {\n        this.divisionId = divisionId;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getGender() {\n        return gender;\n    }\n\n    public void setGender(String gender) {\n        this.gender = gender;\n    }\n\n    public String getMobilephone() {\n        return mobilephone;\n    }\n\n    public void setMobilephone(String mobilephone) {\n        this.mobilephone = mobilephone;\n    }\n\n    public String getTelephone() {\n        return telephone;\n    }\n\n    public void setTelephone(String telephone) {\n        this.telephone = telephone;\n    }\n\n    public Integer getUserType() {\n        return userType;\n    }\n\n    public void setUserType(Integer userType) {\n        this.userType = userType;\n    }\n\n    public String getCreateBy() {\n        return createBy;\n    }\n\n    public void setCreateBy(String createBy) {\n        this.createBy = createBy;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public String getUpdateBy() {\n        return updateBy;\n    }\n\n    public void setUpdateBy(String updateBy) {\n        this.updateBy = updateBy;\n    }\n\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n\n    public Integer getDisabled() {\n        return disabled;\n    }\n\n    public void setDisabled(Integer disabled) {\n        this.disabled = disabled;\n    }\n\n    public String getTheme() {\n        return theme;\n    }\n\n    public void setTheme(String theme) {\n        this.theme = theme;\n    }\n\n    public Integer getIsLdap() {\n        return isLdap;\n    }\n\n    public void setIsLdap(Integer isLdap) {\n        this.isLdap = isLdap;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/config/DBConfig.java",
    "content": "package com.us.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n    @Autowired\n    private Environment env;\n\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/config/JpaConfig.java",
    "content": "package com.us.example.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n@Configuration\n@EnableJpaRepositories(\"com.us.example.dao\")\n@EnableTransactionManagement\n@ComponentScan\npublic class JpaConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean\n    public EntityManagerFactory entityManagerFactory() {\n        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();\n        //vendorAdapter.setShowSql(true);\n        //vendorAdapter.setGenerateDdl(true);\n\n        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();\n        factory.setJpaVendorAdapter(vendorAdapter);\n        factory.setPackagesToScan(\"com.us.example.bean\");\n        factory.setDataSource(dataSource);\n\n\n        Map<String, Object> jpaProperties = new HashMap<String, Object>();\n        jpaProperties.put(\"hibernate.ejb.naming_strategy\",\"org.hibernate.cfg.ImprovedNamingStrategy\");\n        jpaProperties.put(\"hibernate.jdbc.batch_size\",50);\n        //jpaProperties.put(\"hibernate.show_sql\",true);\n\n        factory.setJpaPropertyMap(jpaProperties);\n        factory.afterPropertiesSet();\n        return factory.getObject();\n    }\n\n    @Bean\n    public PlatformTransactionManager transactionManager() {\n\n        JpaTransactionManager txManager = new JpaTransactionManager();\n        txManager.setEntityManagerFactory(entityManagerFactory());\n        return txManager;\n    }\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/controller/UserController.java",
    "content": "package com.us.example.controller;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n\nimport com.us.example.service.UserService;\nimport com.us.example.util.CommonUtil;\n\n\n@Controller\n@RequestMapping(value = \"/users\")\npublic class UserController {\n    private static final Logger logger = Logger.getLogger(UserController.class);\n\n    @Autowired\n    private UserService userService;\n\n\n\n    /**\n     * 通过spring data jpa 调用方法\n     * api :localhost:8099/users/byname?username=xxx\n     * @param request\n     * @return\n     */\n    @RequestMapping(value = \"/byname\", method = RequestMethod.GET)\n    @ResponseBody\n    public ResponseEntity<Object> getUser(HttpServletRequest request) {\n        Map<String, Object> map = CommonUtil.getParameterMap(request);\n        String username = (String) map.get(\"username\");\n        return new ResponseEntity<>(userService.getUserByName(username), HttpStatus.OK);\n    }\n\n\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/dao/UserJpaDao.java",
    "content": "package com.us.example.dao;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\n\nimport com.us.example.bean.User;\n\n/**\n * The Interface UserJpaDao.\n * @author abel\n */\npublic interface UserJpaDao extends JpaRepository<User, Long> {\n\n    /**\n     * Find by name.\n     *\n     * @param name the name\n     * @return the user\n     */\n    User findByName(String name);\n\n\n}"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/service/UserService.java",
    "content": "package com.us.example.service;\n\nimport java.util.Map;\n\nimport com.us.example.bean.User;\n\n/**\n * The Interface UserService.\n */\npublic interface UserService {\n\n\t/**\n\t * Gets the user by name.\n\t *\n\t * @param username the user name\n\t * @return the user by name\n\t */\n\tpublic User getUserByName(String username);\n\t\n\t\n}\n"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/serviceImpl/UserServiceImpl.java",
    "content": "package com.us.example.serviceImpl;\n\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.us.example.dao.UserJpaDao;\nimport com.us.example.bean.User;\nimport com.us.example.service.UserService;\n\n/**\n * \n * @ClassName UserServiceImpl\n * @author abel\n * @date 2016年11月10日\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\t@Autowired\n\tprivate UserJpaDao userJpaDao;\n\t/**\n\t * \n\t * @param username\n\t * @return\n\t */\n\t@Override\n\tpublic User getUserByName(String username) {\n\t\treturn userJpaDao.findByName(username);\n\t}\n}\n"
  },
  {
    "path": "springboot-jpa/src/main/java/com/us/example/util/CommonUtil.java",
    "content": "package com.us.example.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang3.StringUtils;\n\npublic  class CommonUtil {\n\n    /**\n     * 从request中获得参数Map，并返回可读的Map.\n     *\n     * @param request the request\n     * @return the parameter map\n     */\n    public static Map<String, Object> getParameterMap(HttpServletRequest request) {\n        // 参数Map\n        Map<String, String[]> properties = request.getParameterMap();\n        //返回值Map\n        Map<String, Object> returnMap = new HashMap<String, Object>();\n        Set<String> keySet = properties.keySet();\n        for(String key: keySet){\n            String[] values = properties.get(key);\n            String value = \"\";\n            if(values != null && (values.length==1&&StringUtils.isNotBlank(values[0]))?true:false){\n                for(int i=0;i<values.length;i++){\n                    if(values[i] != null && !\"\".equals(values[i])){\n//\t\t\t\t\t\t\tvalue = new String(values[i].getBytes(\"ISO-8859-1\"),\"UTF-8\") + \",\";\n                        value += values[i] + \",\";\n                    }\n                }\n                if(value != null && !\"\".equals(value)){\n                    value = value.substring(0, value.length()-1);\n                }\n                if(key.equals(\"keywords\")){//关键字特殊查询字符转义\n                    value =  value.replace(\"_\", \"\\\\_\").replace(\"%\", \"\\\\%\");\n                }\n                returnMap.put(key, value);\n            }\n        }\n        return returnMap;\n    }\n\n}"
  },
  {
    "path": "springboot-jpa/src/main/resources/application.properties",
    "content": "server.port=8099\r\n\r\nms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/msm?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500"
  },
  {
    "path": "springboot-kafka/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-kafka</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.40</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.springframework.kafka</groupId>\n            <artifactId>spring-kafka</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-kafka/src/main/java/cn/abel/Application.java",
    "content": "package cn.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;\n\n/**\n * Created by yyb on 2018/12/12.\n */\n@SpringBootApplication(exclude = KafkaAutoConfiguration.class)\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-kafka/src/main/java/cn/abel/config/KafkaConfig.java",
    "content": "package cn.abel.config;\n\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.EnableKafka;\nimport org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;\nimport org.springframework.kafka.config.KafkaListenerContainerFactory;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by yyb on 2018/12/12.\n */\n@Configuration\n@EnableKafka\npublic class KafkaConfig {\n\n    /**\n     * kafka地址\n     */\n    @Value(\"${spring.kafka.bootstrap-servers}\")\n    private String bootstrapServers;\n    /**\n     * 默认组\n     */\n    @Value(\"${spring.kafka.consumer.group-id}\")\n    private String groupId;\n    /**\n     * 自动消费设定\n     */\n    @Value(\"${spring.kafka.consumer.auto-offset-reset}\")\n    private String autoOffsetReset;\n    /**\n     * 一次批量处理的数据量\n     */\n    @Value(\"${spring.kafka.consumer.max-poll-records}\")\n    private int maxPollRecords;\n    /**\n     * 一次批量处理的时间间隔\n     */\n    @Value(\"${spring.kafka.consumer.max-poll-interval-ms}\")\n    private int maxPollIntervalMs;\n\n    @Value(\"${spring.kafka.listener.concurrency}\")\n    private int cocurrency;\n\n    @Value(\"${spring.kafka.consumer.auto-commit-interval}\")\n    private Integer commitInterval;\n\n    @Bean(name = \"kafkaListenerContainerFactory\")\n    public KafkaListenerContainerFactory<?> batchFactory() {\n        ConcurrentKafkaListenerContainerFactory<String, String> factory =\n                new ConcurrentKafkaListenerContainerFactory<>();\n        factory.setConsumerFactory(consumerFactory());\n        factory.setConcurrency(cocurrency);\n        //设置为批量消费，每个批次数量在Kafka配置参数中设置ConsumerConfig.MAX_POLL_RECORDS_CONFIG\n        factory.setBatchListener(true);\n        return factory;\n    }\n\n    @Bean\n    public ConsumerFactory<String, String> consumerFactory() {\n        return new DefaultKafkaConsumerFactory<>(consumerConfigs());\n    }\n    @Bean\n    public Map<String, Object> consumerConfigs() {\n        Map<String, Object> props = new HashMap<>();\n        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);\n        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);\n        props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, commitInterval);\n        props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, \"15000\");\n        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);\n        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);\n        props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);\n        //每一批数量\n        props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords);\n        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);\n        return props;\n    }\n\n\n}\n"
  },
  {
    "path": "springboot-kafka/src/main/java/cn/abel/service/prehandle/KafkaConsumerService.java",
    "content": "package cn.abel.service.prehandle;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n/**\n * Created by yyb on 2018/12/10.\n */\n\n@Component\npublic class KafkaConsumerService {\n\n    @Autowired\n    private SplitService splitService;\n\n    @KafkaListener(topics = \"${log.statistical.kafka.topic}\", containerFactory = \"kafkaListenerContainerFactory\")\n    public void processMessage(List<ConsumerRecord<?, ?>> records) {\n\n        for (ConsumerRecord<?, ?> record : records) {\n            String message = (String) record.value();\n            splitService.saveAndSplitLog(message);\n        }\n    }\n}\n"
  },
  {
    "path": "springboot-kafka/src/main/java/cn/abel/service/prehandle/SplitService.java",
    "content": "package cn.abel.service.prehandle;\n\n\nimport com.alibaba.fastjson.JSONObject;\nimport lombok.extern.slf4j.Slf4j;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created by yyb on 2018/12/10.\n */\n@Service\n@Slf4j\npublic class SplitService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SplitService.class);\n\n    public void saveAndSplitLog(String message) {\n        JSONObject jsonObject = JSONObject.parseObject(message);\n        // 从kafka 中获取到数据\n        String content = jsonObject.getString(\"message\");\n    }\n\n}\n"
  },
  {
    "path": "springboot-kafka/src/main/resources/local/application.properties",
    "content": "server.port=8090\nspring.kafka.bootstrap-servers=127.0.0.1:9092\nspring.kafka.consumer.group-id=springboot-kafka\nspring.kafka.consumer.auto-offset-reset=latest\nspring.kafka.consumer.enable-auto-commit=true\nspring.kafka.consumer.auto-commit-interval=2000\nspring.kafka.listener.concurrency= 1\nspring.kafka.consumer.max-poll-records=50\nspring.kafka.consumer.max-poll-interval-ms=4000\n# topic\nlog.statistical.kafka.topic=nginx_log\n\n\nlogging.file=./logs/springboot-kafka.log\n\n\n\n\n"
  },
  {
    "path": "springboot-kafka/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-kafka/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-kafka</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>30</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n\n    <logger name=\"org.apache\" level=\"INFO\"/>\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-mybatis/docker-it.sh",
    "content": "#!/bin/sh\n\n#########################\n# based on docker bin\n\npackageName=$1\nimageVersion=$2\ndockerDestFolder=$3\nenv=$4\npackageTZ=Asia/Shanghai\n\nif [ \"${packageName}\" = \"\" ]; then\n    echo [ERROR] \"Please provide image name as first param\"\n    exit 1\nfi\n\nif [ \"${imageVersion}\" = \"\" ]; then\n    echo [ERROR] \"Please provide image version as second param\"\n    exit 1\nfi\n\nif [ \"${dockerDestFolder}\" = \"\" ]; then\n    echo [ERROR] \"Please provide docker dest folder\"\n    exit 1\nfi\n\nif [ \"${env}\" = \"\" ]; then\n    echo [ERROR] \"Please provide env folder\"\n    exit 1\nfi\n\n\nCOUNT=`docker -v 2>&1 | grep 'version' |  grep -v grep | wc -l`\nif [ ${COUNT} != 1 ]; then\n    echo [ERROR] \"Cannot find docker command\"\n    exit 1\nfi\n\necho [INFO] \"Remove old image from docker repository...\"\ncount=`docker images | grep \"${packageName}\" | grep \"${imageVersion}\" | wc -l`\nif [ ${count} != 1 ]; then\n  echo [WARN] \"image ${packageName} with version ${imageVersion} does not exist in docker repo\"\nelse\n  docker rmi -f ${packageName}:${imageVersion}\nfi\n\n#generate Dockerfile dynamically\necho [INFO] \"generating Dockerfile...\"\nwarName=${packageName}-${imageVersion}.war\ndateVersion=`date +%Y%m%d-%H%M%S`\n\n#cat out to Dockerfile with content begin/end with EOF\ncat > target/Dockerfile <<EOF\nFROM debian:jessie\nMAINTAINER Cliff Ma\nCOPY target/${warName} ${dockerDestFolder}/${dateVersion}/\nENV LANG C.UTF-8\nENV TZ=Asia/Shanghai\nRUN ln -snf /usr/share/zoneinfo/${packageTZ} /etc/localtime && echo ${packageTZ} > /etc/timezone\nRUN cd ${dockerDestFolder} \\\n    && ln -svnf ${dateVersion} current \\\n    && cd current \\\n    && touch docker-entrypoint.sh \\\n    && chmod +x docker-entrypoint.sh \\\n    && echo \"/opt/apps/java/bin/java -jar ${dockerDestFolder}/current/*.war --spring.config.location=${dockerDestFolder}/current/env/application.properties >/dev/null 2>&1\" > docker-entrypoint.sh\nCMD .${dockerDestFolder}/current/docker-entrypoint.sh\nEOF\n\n# echo $TZ > /etc/timezone   TO someString to one file.\n# To set the right time.\n# ENV TZ=Asia/Shanghai\n# RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone\n# COPY conf/${env}/*.cer ${dockerDestFolder}/${dateVersion}/\n\n\n#read Dockerfile\necho [INFO] \"Building image...\"\ndocker build -t ${packageName}:${imageVersion} -f target/Dockerfile . || exit 1\n\n\necho [INFO] \"Exporting image to target folder...\"\ndocker save ${packageName}:${imageVersion} > target/${packageName}-${imageVersion}.image\n\n\n"
  },
  {
    "path": "springboot-mybatis/env/dev/application.properties",
    "content": "# EMBEDDED SERVER CONFIGURATION (ServerProperties) \r\nserver.port=8099\r\n\r\n\r\nms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/msm?useSSL=false&useUnicode=true&characterEncoding=UTF-8\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500"
  },
  {
    "path": "springboot-mybatis/env/dev/env.properties",
    "content": "#dev\n\n################\n##this property file is used to export shell session-scoped variables by command 'source *.properties'\n################\n\n#app root\nprop_appRoot=/opt/apps\n\n\n#run postinstall or not.(It is not used any more.)\nprop_runPreinstall=false\nprop_runPostinstall=false\n\n#the package name\nprop_package=springboot-mybatis\n#the package version\nprop_packageVersion=v1\n\n\n#Your Java Home\nprop_javaHome=/opt/apps/jdk/current\n\n#owner and group for package\nprop_ownerGroup=root:root\n\n\n#folders which need to be created manually, the folder path will be relative to the app home folder\n#seperate multi folders with space, don't forget the double \"\nprop_manualFolders=\"var/logs\"\n#manual folders mode\nprop_manualFolderMode=777\n\n\n###################\n#Cluster config\n###################\n#used by install.sh to decide the install mode: cluster or single node(default false)\nprop_isCluster=false\n\n#single\nprop_singleNode=springboot-mybatis-dev\n\n#cluster\n#all the nodes for the cluster, only is is accepted now\n#seperated by , sign (EX di,d2,192.168.100.2)(If you want to use d1 d2,you must config the url in etc/local)\nprop_clusterNodes=d1\n\n\n###################\n#springboot config\n###################\nprop_springbootWarName=${prop_package}\nprop_springbootWarVersion=${prop_packageVersion}\nprop_springbootProcessKeyWord=${prop_springbootWarName}-${prop_springbootWarVersion}.war\n\n\n##############\n#docker config\n##############\nprop_dockerDestFolder=${prop_appRoot}/${prop_package}\n#docker daemon.(Docker is online or not.)\nprop_dockerProcessKeyWord='docker'\n#docker image name, e.g. cliff/nginx or nginx\nprop_dockerImageName=${prop_package}\n#docker image version, e.g. v1/v2 or latest\nprop_dockerImageVersion=${prop_packageVersion}\n#docker container count in each host server(1 in most situation.)\nprop_dockerContainerCount=1\n\n#docker config file mapping, multiple file mappings is supported so you can specify multiple -v xx:xx\nprop_dockerConfigFileMapping=\"env:${prop_dockerDestFolder}/current/env\"\nprop_dockerLogFolderMapping=\"var/logs/nodexxx:${prop_dockerDestFolder}/var/logs\"\nprop_dockerUploadFolderMapping=\"uploadFiles:${prop_dockerDestFolder}/uploadFiles\"\n# It is not used any more. Add command `--net=host` \nprop_dockerPortMappings=80:8081\n\n##########################################\n#seconds config before start and stop\n##########################################\n\n#the sleep time to wail for each node starting up after another, the unit is second\nprop_startAllSleep=2\n\n#the sleep time to wail for one node starting up. \n#sometimes we start up server by backend job so we need wait some time\nprop_startOneSleep=8\n\n#stop node timeout, if timeout we will kill -9, the unit is second\nprop_stopNodeTimeout=2"
  },
  {
    "path": "springboot-mybatis/env/dev/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message\r\nlog4j.rootLogger=INFO, Console, R\r\n\r\n#Console\r\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\r\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\nlog4j.appender.R=org.apache.log4j.RollingFileAppender\r\nlog4j.appender.R.File=logs/cmbms.log\r\nlog4j.appender.R.MaxFileSize=50kB\r\nlog4j.appender.R.MaxBackupIndex=5\r\nlog4j.appender.R.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.R.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\nlog4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender \r\nlog4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd \r\nlog4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout \r\n#log4j.appender.ServerDailyRollingFile.Append=true\r\n\r\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender \r\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout \r\nlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n\r\n\r\n"
  },
  {
    "path": "springboot-mybatis/env/local/application.properties",
    "content": "# EMBEDDED SERVER CONFIGURATION (ServerProperties) \r\nserver.port=8099\r\n\r\n\r\nms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/msm?useSSL=false&useUnicode=true&characterEncoding=UTF-8\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500"
  },
  {
    "path": "springboot-mybatis/env/local/env.properties",
    "content": "#local\n\n################\n##this property file is used to export shell session-scoped variables by command 'source *.properties'\n################\n\n#app root\nprop_appRoot=/opt/apps\n\n\n#run postinstall or not.(It is not used any more.)\nprop_runPreinstall=false\nprop_runPostinstall=false\n\n#the package name\nprop_package=springboot-mybatis\n#the package version\nprop_packageVersion=v1\n\n\n#Your Java Home\nprop_javaHome=/opt/apps/java/Contents/Home\n\n#owner and group for package\nprop_ownerGroup=root:root\n\n\n#folders which need to be created manually, the folder path will be relative to the app home folder\n#seperate multi folders with space, don't forget the double \"\nprop_manualFolders=\"var/logs\"\n#manual folders mode\nprop_manualFolderMode=777\n\n\n###################\n#Cluster config\n###################\n#used by install.sh to decide the install mode: cluster or single node(default false)\nprop_isCluster=false\n\n#single\nprop_singleNode=local\n\n#cluster\n#all the nodes for the cluster, only is is accepted now\n#seperated by , sign (EX di,d2,192.168.100.2)(If you want to use d1 d2,you must config the url in etc/local)\nprop_clusterNodes=d1\n\n\n###################\n#springboot config\n###################\nprop_springbootWarName=${prop_package}\nprop_springbootWarVersion=${prop_packageVersion}\nprop_springbootProcessKeyWord=${prop_springbootWarName}-${prop_springbootWarVersion}.war\n\n\n##############\n#docker config\n##############\nprop_dockerDestFolder=${prop_appRoot}/${prop_package}\n#docker daemon.(Docker is online or not.)\nprop_dockerProcessKeyWord='docker'\n#docker image name, e.g. cliff/nginx or nginx\nprop_dockerImageName=${prop_package}\n#docker image version, e.g. v1/v2 or latest\nprop_dockerImageVersion=${prop_packageVersion}\n#docker container count in each host server(1 in most situation.)\nprop_dockerContainerCount=1\n\n#docker config file mapping, multiple file mappings is supported so you can specify multiple -v xx:xx\nprop_dockerConfigFileMapping=\"env:${prop_dockerDestFolder}/current/env\"\nprop_dockerLogFolderMapping=\"var/logs/nodexxx:${prop_dockerDestFolder}/var/logs\"\nprop_dockerUploadFolderMapping=\"uploadFiles:${prop_dockerDestFolder}/uploadFiles\"\nprop_dockerPortMappings=8080:8080\n\n##########################################\n#seconds config before start and stop\n##########################################\n\n#the sleep time to wail for each node starting up after another, the unit is second\nprop_startAllSleep=2\n\n#the sleep time to wail for one node starting up. \n#sometimes we start up server by backend job so we need wait some time\nprop_startOneSleep=8\n\n#stop node timeout, if timeout we will kill -9, the unit is second\nprop_stopNodeTimeout=2"
  },
  {
    "path": "springboot-mybatis/env/local/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message\r\nlog4j.rootLogger=INFO, Console, R\r\n\r\n#Console\r\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\r\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\nlog4j.appender.R=org.apache.log4j.RollingFileAppender\r\nlog4j.appender.R.File=logs/cmbms.log\r\nlog4j.appender.R.MaxFileSize=50kB\r\nlog4j.appender.R.MaxBackupIndex=5\r\nlog4j.appender.R.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.R.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\nlog4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender \r\nlog4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd \r\nlog4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout \r\n#log4j.appender.ServerDailyRollingFile.Append=true\r\n\r\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender \r\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout \r\nlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n\r\n\r\n"
  },
  {
    "path": "springboot-mybatis/package.sh",
    "content": "#!/bin/bash\n\n#####################\n# bash only\n# usage ./package.sh\n#####################\n\n#declare -a: define an array\n#declare -i: define an integer\ndeclare -i index=1\ndeclare -a envMap\ndeclare -a formatMap=([\"1\"]=\"docker\" [\"2\"]=\"springboot\")\n\n#GET THE URL OF CURRENT PATH\nCURRENT_DIR=`dirname $0`\ncd $CURRENT_DIR\n\n#########################\n# confirm the env \n#########################\nindex=1\n#scan the envs from conf/*\nfor i in env/* ; do \n if [ -d ${i} ]; then\n\tenvMap[\"${index}\"]=\"`basename ${i}`\"\n\tindex=index+1\n fi\ndone\n\n#Print the choice\nenv=1\necho \"Please choose the environment by typing the number [default ${env}]\"\nfor i in ${!envMap[@]} ;do\n\techo [${i}]:${envMap[${i}]}\ndone\n\n#Read the envTmp . Set The finalEnv. Pay Attention 'read' NOT 'Read'\nread envTmp\n# echo \"${envTmp}\"\nif [ \"${envTmp}\" != \"\" ]; then\n  env=${envTmp}\nfi\n# echo \"${env}\"\nfinalEnv=${envMap[${env}]}\necho \"${finalEnv}\"\necho \"[INFO] You are choosing environment: ${finalEnv}\"\necho \"[INFO] Set the env properties by env/${finalEnv}/env.properties\"\n\n#Load the env/${finalEnv}/env.properties\n. env/${finalEnv}/env.properties\necho \"\"\necho \"\"\n\n#########################\n# confirm the format \n#########################\nformat=1\nfor i in ${!formatMap[@]};do\n\techo [${i}]: ${formatMap[${i}]}\ndone\nread formatTmp\nif [ \"${formatTmp}\" != \"\" ]; then\n  format=${formatTmp}\nfi\nfinalFormat=${formatMap[${format}]}\n#########################\n# confirm the package \n#########################\nfinalPackage=${prop_package}\necho \"[INFO] You are choosing package version: ${finalPackage}\" \necho \"\"\necho \"\"\n\n#########################\n# confirm the version \n#########################\nfinalPackageVersion=${prop_packageVersion}\necho \"[INFO] You are choosing package version: ${finalPackageVersion}\" \necho \"\"\necho \"\"\n\n######################\n# begin packing\n######################\nif [ -n \"${finalFormat}\" ] && [ \"${finalFormat}\" = \"springboot\" ]; then\n\t##############################\n\t# generate executable war file\n\t##############################\n\n\t#noneed.properties The .properties is outside the war . So it is no need any more.\n\ttheCommand=\"./war-it.sh ${finalPackage} ${finalPackageVersion} ${finalEnv} 'noneed.properties'\"\n\techo [INFO] ${theCommand}\n\teval ${theCommand} || exit 1\nelse\n\t##############################\n\t# generate executable war file\n\t##############################\n\ttheCommand=\"./war-it.sh ${finalPackage} ${finalPackageVersion} ${finalEnv} 'noneed.properties'\"\n\techo [INFO] ${theCommand}\n\teval ${theCommand} || exit 1\n\t\n\t\n\t\n\t#####################################\n\t# generate docker image and export it\n\t#####################################\n\ttheCommand=\"./docker-it.sh ${finalPackage} ${finalPackageVersion} ${prop_dockerDestFolder} ${finalEnv}\"\n\techo [INFO] ${theCommand}\n\teval ${theCommand} || exit 1\nfi\n\ntheCommand=\"./tar-it.sh ${finalEnv} ${finalPackage} ${finalPackageVersion} ${finalFormat}\"\necho [INFO] ${theCommand}\neval ${theCommand} || exit 1\n\necho \"[INFO] package is done successfully\"\n\n"
  },
  {
    "path": "springboot-mybatis/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.u</groupId>\n    <artifactId>springboot-mybatis</artifactId>\n    <version>v1</version>\n    <packaging>war</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n    <properties>\n        <start-class>com.us.example.Application</start-class>\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n        <!--util-->\n        <dependency>\n            <groupId>com.jf</groupId>\n            <artifactId>page-mysql</artifactId>\n            <version>1.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n        <!--Test-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--log-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-log4j</artifactId>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <mainClass>${start-class}</mainClass>\n                </configuration>\n            </plugin>\n            <!-- to generate excutable jar/war with springboot style end -->\n\n            <!-- to generate executable jar/war with standard style begin -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-war-plugin</artifactId>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <mainClass>${start-class}</mainClass>\n                        </manifest>\n                    </archive>\n                    <webappDirectory>${project.build.directory}/springboot-mybatisma</webappDirectory>\n                    <warSourceDirectory>src/main/webapp</warSourceDirectory>\n                    <webResources>\n                        <resource>\n                            <directory>env/${package.environment}</directory>\n                            <includes>\n                                <include>${package.resources}</include>\n                            </includes>\n                            <targetPath>WEB-INF/classes</targetPath>\n                        </resource>\n                    </webResources>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>default-war</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>war</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- to generate executable jar/war with standard style end -->\n\n            <!-- to generate compressed package（tar package） specified by package.xml begin -->\n            <plugin>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.5.5</version>\n                <configuration>\n                    <finalName>${package}-${package.version}</finalName>\n                    <ignorePermissions>true</ignorePermissions>\n                    <appendAssemblyId>false</appendAssemblyId>\n                    <descriptors>\n                        <descriptor>${basedir}/scripts/${package.format}/common/package.xml</descriptor>\n                    </descriptors>\n                </configuration>\n            </plugin>\n            <!-- to generate compressed package specified by package.xml end -->\n\n            <!-- resource插件, 设定编码，防止中文乱码 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <configuration>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                </configuration>\n            </plugin>\n\n            <!--test plugin begin -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <configuration>\n                    <!-- method level parallel -->\n                    <parallel>methods</parallel>\n                    <threadCount>10</threadCount>\n                    <argLine>-Dfile.encoding=UTF-8</argLine>\n                    <!-- if want junit test before packaging, set it to be false -->\n                    <!-- if the skipTests is false, and the junit test is wrong. The packaging will be stopped. -->\n                    <skipTests>true</skipTests>\n                    <includes>\n                        <include>**/*Test.java</include>\n                    </includes>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>default-test</id>\n                        <phase>test</phase>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <!--&lt;!&ndash;打依赖包&ndash;&gt;-->\n            <!--<plugin>-->\n                <!--<groupId>org.apache.maven.plugins</groupId>-->\n                <!--<artifactId>maven-shade-plugin</artifactId>-->\n                <!--<version>2.3</version>-->\n                <!--<executions>-->\n                    <!--<execution>-->\n                        <!--<phase>package</phase>-->\n                        <!--<goals>-->\n                            <!--<goal>shade</goal>-->\n                        <!--</goals>-->\n                    <!--</execution>-->\n                <!--</executions>-->\n            <!--</plugin>-->\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-mybatis/scripts/docker/common/common-env.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n#SCRIPT_PATH must be defined firstly by calling script\necho \"[INFO] calling common-env.sh\"\nif [ \"${SCRIPT_PATH}\" = \"\" ]; then\n  echo \"[ERROR] SCRIPT_PATH is not defined in calling script\"\n  exit 1\nelse\n    #############\n\t# define own function\n\t#############\n\t\n\t#print out command into console (and log file if there is one) and then execute it\n\tmyexecute () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theCommand=${1}\n\t  echo \"${dt}: [COMMAND] ${theCommand}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: [COMMAND] ${theCommand}\" >> ${LOG}\n\t  fi\n\t  \n\t  ${theCommand}\n\t  return $?\n\t}\n\t\n\tmyexecute2 () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theCommand=${1}\n\t  echo \"${dt}: [COMMAND] ${theCommand}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: [COMMAND] ${theCommand}\" >> ${LOG}\n\t  fi\n\t  \n\t  eval ${theCommand}\n\t  return $?\n\t}\n\t\n\t#print out log into console (and log file if there is one)\n\tmylog () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theLog=${1}\n\t  echo \"${dt}: ${theLog}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: ${theLog}\" >> ${LOG}\n\t  fi\n\t  \n\t}\n\t\n\t#print out log into console (and log file if there is one), and transate \\n into new line\n\tmylog2 () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theLog=${1}\n\t  echo -e \"${dt}: ${theLog}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo -e \"${dt}: ${theLog}\" >> ${LOG}\n\t  fi\n\t  \n\t}\n\t\n\t#check it is a number or not\n\tisNumber () {\n\t  var=${1}\n\t  if [ ${var} -eq ${var} 2> /dev/null ]\n\t  then\n\t    return 0\n\t  else\n\t    return 1\n\t  fi\n    }\n    \n    \n\n\t############\n\t# to export variables\n\t############\n\t\n\t#export all variables in env.properties\n\techo \"[INFO] export all variables in env.properties\"\n\tif [ -f ${SCRIPT_PATH}/../env/env.properties ]; then\n\t  myexecute \"source ${SCRIPT_PATH}/../env/env.properties\"\n\telif [ -f ${SCRIPT_PATH}/../env/env.properties ]; then\n\t  myexecute \"source ${SCRIPT_PATH}/../env/env.properties\"\n\telse\n\t  echo \"[ERROR] cannot find env.properties\"\n\t  exit 1\n\tfi\n\t\nfi\n\n\necho \"[INFO] common-env.sh is done\"\n\n#exit 0 is not allowed here which is stop calling script from going on executing \n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/common/install-cluster.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used for cluster install\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\nif [ \"${prop_runPreinstall}\" = \"true\" ]; then\n    myexecute \"${SCRIPT_PATH}/preinstall.sh\"\n    if [ $? != 0 ]; then\n      exit 1\n    fi\nfi\n\nmylog \"[INFO] Begin install-cluster.sh\"\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\nAPPROOT=${prop_appRoot}\nAPPNAME=${prop_package}\nAPPHOME=${APPROOT}/${APPNAME}\nHOSTNAME=`hostname`\n\n\nCLUSTER_NODES=${prop_clusterNodes}\n#replace ',' with space\nCLUSTER_NODES=${CLUSTER_NODES//,/ }\n#replace '\"' with null\nCLUSTER_NODES=${CLUSTER_NODES//\\\"/}\n\nMANUAL_FOLDERS=${prop_manualFolders}\nMANUAL_FOLDER_MODE=${prop_manualFolderMode}\n\n\n\nfor i in ${CLUSTER_NODES}\ndo\n  mylog \"\"\n  mylog \"-----------------------------\"\n  mylog \"[INFO] Connecting to host ${i}\"\n  \n  \n  #create app home folder and new version folder\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} mkdir -p ${APPHOME}/${APPVERSION}\"\n  mylog \"[INFO] Folder ${APPHOME}/${APPVERSION} is created successfully on host <<${i}>>\" \n\n  #copy files from current host to another node by scp command\n  #-p preserves modification times, access times, and modes from the original file\n  mylog \"[INFO] copying files to host <<${i}>> by scp command\"\n  myexecute \"scp -rp ${SCRIPT_PATH}/../* root@${i}:${APPHOME}/${APPVERSION}/\"\n  mylog \"[INFO] Copy is done!\"\n  \n  #change owner and group for app package\n  mylog \"[INFO] changing owner and group recursively\"\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} chown -R ${prop_ownerGroup} ${APPHOME}/${APPVERSION}/\"\n  mylog \"[INFO] Owner and group set up done!\"\n  \n  #create manual folders\n  if [ \"${MANUAL_FOLDERS}\" != \"\" ]; then\n      theCommand=\"ssh -oStrictHostKeyChecking=no root@${i} \\\"pwd \"\n      for MANUAL_FOLDER in ${MANUAL_FOLDERS}\n\t  do\n\t      theCommand=\"${theCommand} && mkdir -p ${APPHOME}/${MANUAL_FOLDER}\"\n\t\t  if [ \"${MANUAL_FOLDER_MODE}\" != \"\" ]; then\n\t\t    theCommand=\"${theCommand} && chmod -R ${MANUAL_FOLDER_MODE} ${APPHOME}/${MANUAL_FOLDER}\"\n\t\t  fi\n\t  done\n\t  theCommand=\"${theCommand} \\\" \"\n\t  myexecute2 \"${theCommand}\"\n  fi\n  \n  #create soft link named 'current', -s:soft link -v:debug mode -n:treate link as normal file if it linking to a folder\n  #-f:force create it is already there\n  mylog \"[INFO] Create soft link named 'current'\"\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} ln -svnf ${APPHOME}/${APPVERSION} ${APPHOME}/current\"\n  mylog \"[INFO] Link creation is done!\"\n  \n  if [ \"${prop_runPostinstall}\" = \"true\" ]; then\n    myexecute \"ssh -oStrictHostKeyChecking=no root@${i} ${APPHOME}/current/scripts/postinstall.sh\"\n    mylog \"[INFO] postinstall is done on node ${i}\"\n  fi\n\n  mylog \"--------------------------------\"\ndone\n\nmylog \"[INFO] Cluster installation is done successfully, for more detail please check log ${LOG}\"\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/common/install-single.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used for single server install\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nif [ \"${prop_runPreinstall}\" = \"true\" ]; then\n  myexecute \". ${SCRIPT_PATH}/preinstall.sh\"\n  if [ $? != 0 ]; then\n      exit 1\n  fi\nfi\t\n\nmylog \"[INFO] Begin install-single.sh\"\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\n\n\nAPPROOT=${prop_appRoot}\nAPPNAME=${prop_package}\nAPPHOME=${APPROOT}/${APPNAME}\nHOSTNAME=`hostname`\n\n\nSINGLE_NODE=${prop_singleNode}\nMANUAL_FOLDERS=${prop_manualFolders}\nMANUAL_FOLDER_MODE=${prop_manualFolderMode}\n\n\nmylog \"\"\nmylog \"-----------------------------\"\nmylog \"[INFO] Installing on host ${SINGLE_NODE}\"\n\n\n#create app home folder and new version folder\nmyexecute \"mkdir -p ${APPHOME}/${APPVERSION}\"\nmylog \"[INFO] Folder ${APPHOME}/${APPVERSION} is created successfully on host <<${SINGLE_NODE}>>\" \n\n#copy files from current folder to app home folder\n#-p reserve the specified attributes (default: mode,ownership,timestamps)\nmylog \"[INFO] copying files to host <<${SINGLE_NODE}>> by cp command\"\nmyexecute \"cp -rp ${SCRIPT_PATH}/../* ${APPHOME}/${APPVERSION}/\"\nmylog \"[INFO] Copy is done!\"\n\n#change owner and group for app package\nmylog \"[INFO] changing owner and group recursively\"\nmyexecute \"chown -R ${prop_ownerGroup} ${APPHOME}/${APPVERSION}\"\nmylog \"[INFO] Owner and group set up done!\"\n\n#create manual folders\nif [ \"${MANUAL_FOLDERS}\" != \"\" ]; then\n  for MANUAL_FOLDER in ${MANUAL_FOLDERS}\n  do\n\t  myexecute \"mkdir -p ${APPHOME}/${MANUAL_FOLDER}\"\n\t\n\t  if [ \"${MANUAL_FOLDER_MODE}\" != \"\" ]; then\n\t    myexecute \"chmod -R ${MANUAL_FOLDER_MODE} ${APPHOME}/${MANUAL_FOLDER}\"\n\t  fi\n  done\nfi\n\n#create soft link named 'current', -s:soft link -v:debug mode -n:treate link as normal file if it linking to a folder\n#-f:force create it ignoring if it is already there\nmylog \"[INFO] Create soft link named 'current'\"\nmyexecute \"ln -svnf ${APPHOME}/${APPVERSION} ${APPHOME}/current\"\nmylog \"[INFO] Link creation is done!\"\nmylog \"--------------------------------\"\n\nmylog \"[INFO] Installation is done successfully, for more detail please check log ${LOG}\"\nmylog \"------------------------------------\"\nmylog \"------------------------------------\"\n\nif [ \"${prop_runPostinstall}\" = \"true\" ]; then\n  myexecute \". ${SCRIPT_PATH}/postinstall.sh\"\nfi\n\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/common/install.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used to install package\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    export SCRIPT_PATH=${PWD}\n    echo \"[INFO] export SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\n\nmylog \"[INFO] Begin install.sh\"\n\n#check it is a single node installation or a cluster installation\nif [ \"${prop_isCluster}\" = \"true\" ]; then\n  mylog \"[INFO] checked you are doing CLUSTER installation\"\n  myexecute \"${SCRIPT_PATH}/install-cluster.sh\"\nelse\n  mylog \"[INFO] checked you are doing SINGLE NODE installation\"\n  myexecute \"${SCRIPT_PATH}/install-single.sh\"\nfi\n\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/common/package.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3\" \n  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 \n  http://maven.apache.org/xsd/assembly-1.1.3.xsd\">\n  \n    <id>0.1</id>\n    <formats>\n        <format>tar</format>\n    </formats>\n      \n    <fileSets>\n        <fileSet>\n            <directory>scripts/${package.format}/manager</directory>\n            <outputDirectory>/scripts</outputDirectory>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>scripts/${package.format}/common</directory>\n            <outputDirectory>/scripts</outputDirectory>\n            <fileMode>0755</fileMode>\n            <includes>\n              <include>install-cluster.sh</include>\n              <include>install-single.sh</include>\n              <include>install.sh</include>\n              <include>common-env.sh</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>env/${package.environment}</directory>\n            <outputDirectory>/env</outputDirectory>\n        </fileSet>\n    </fileSets>\n    \n     <files>\n\t\t<file>\n\t\t\t<source>target/${package}-${package.version}.image</source>\n\t\t\t<outputDirectory>/</outputDirectory>\n\t\t\t<destName>${package}-${package.version}.img.tar</destName>\n\t\t\t<fileMode>0755</fileMode>\n\t\t</file>\n\t </files>\n    \n    \n   \n</assembly>"
  },
  {
    "path": "springboot-mybatis/scripts/docker/manager/check-os.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n#######################\n###for redhat 7 only\n#######################\n\n1. close whole firewall\nissue:\n\tall port like 80/20 and so on cannot be accessed\ncheck:\n\tsystemctl list-unit-files|grep enabled | grep firewall (if not null, firewall is open)\n   \nfix:\n\tsystemctl stop firewalld.service\n\tsystemctl disable firewalld.service\n\t\nrollabck:\n\tsystemctl enable firewalld.service\n\tsystemctl start firewalld.service\n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/manager/setenv.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\necho \"[INFO] calling setenv.sh\"\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n############\n# call common-env.sh\n############\n. ${SCRIPT_PATH}/common-env.sh\n\n\n#other env setup\n#xxx\n#xxx\n\n\necho \"[INFO] setenv.sh is done\"\n\n#exit 0 is not allowed here which will stop calling script from going on executing\n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/manager/start.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nmylog \"[INFO] calling start.sh\"\n\n\nHOSTNAME=`hostname`\nAPPNAME=${prop_package}\nAPPROOT=${prop_appRoot}\nAPPHOME=${APPROOT}/${APPNAME}\nLOG=/tmp/start-${APPNAME}.log\n\n\n\nPROCESS_ID=`ps -ef | grep \"${prop_dockerProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nisNumber ${PROCESS_ID}\n#$? represents the result of last unix command\nnumberCheck=$?\nif [ numberCheck ]; then\n    #kill -0 will send a signal to the process to check if the process exists, 0 menas exists and 1 vice visa\n    if kill -0 ${PROCESS_ID} > /dev/null 2>&1; then\n      mylog \"\"\n    else\n      mylog \"[ERROR]  docker daemon is not running on server <<${HOSTNAME}>>, pleae start it first\"\n      exit 1\n    fi\nfi\n\n#check docker image:version running or not \ncount=`docker ps --no-trunc=true | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} = ${prop_dockerContainerCount} ]; then\n    mylog \"[WARN]  ${prop_dockerContainerCount} containers for ${APPNAME} are already running on server <<${HOSTNAME}>>, will do nothing \"\n    exit 0\nelif [ ${count} = 0 ]; then\n    mylog \"[INFO]  checked no any ${APPNAME} is running on server <<${HOSTNAME}>>\"\nelse\n    mylog \"[ERROR] ${count} containers for ${APPNAME} are already running, but ${prop_dockerContainerCount} is expected. Please check why\"\n    exit 0\nfi\n\n\n\n\n\n\n#check docker image name and version existing or not in doc repo\ncount=`docker images | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} != 0 ]; then\n    mylog \"[INFO] image ${prop_dockerImageName} with version ${prop_dockerImageVersion} already exists in docker repo on host <<${HOSTNAME}>>\"\n    \n    \n    remove=\"yes\"\n    mylog \"[????] Do you want to remove it and reload the image (default ${remove}):\"\n    read removeTmp\n    if [ \"${removeTmp}\" != \"\" ]; then\n\t  \tremove=${removeTmp}\n\tfi\n\t\n\t\n\tif [[ \"yes\" = \"${remove}\" || \"YES\" = \"${remove}\" ]]; then\n\t  \tmylog \"[COMMAND] docker rmi -f  ${prop_dockerImageName}:${prop_dockerImageVersion}\"\n      \tdocker rmi -f  ${prop_dockerImageName}:${prop_dockerImageVersion}\n      \n      \t#check remove result\n\t    count=`docker images | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\n\t    if [ ${count} != 0 ]; then\n\t        mylog \"[ERROR] failed to remove image, please check why or remove it manually\"\n\t        exit 1\n\t    fi\n\tfi\n    \n    \nfi\n\n\ncount=`docker images | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} = 0 ]; then\n    imageTar=${prop_dockerImageName}-${prop_dockerImageVersion}.img.tar\n    mylog \"[WARN]  image ${prop_dockerImageName} with version ${prop_dockerImageVersion} does not exist in docker repo on host <<${HOSTNAME}>>\"\n    mylog \"[COMMAND] docker load < ${APPHOME}/current/${imageTar}\"\n    docker load < ${APPHOME}/current/${imageTar}\n    \n    #check loading result\n    count=`docker images | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\n    if [ ${count} != 1 ]; then\n        mylog \"[ERROR] failed to load image, please check why or load it manually\"\n        exit 1\n    fi\nfi\n\n\nDOCKER_PORT_MAPPINGS=${prop_dockerPortMappings}\n#replace ',' with space\nDOCKER_PORT_MAPPINGS=${DOCKER_PORT_MAPPINGS//,/ }\n\nDOCKER_CONFIG_FOLDER_MAPPING=\"${APPHOME}/current/${prop_dockerConfigFileMapping}\"\nDOCKER_LOG_FOLDER_MAPPING=\"${APPHOME}/${prop_dockerLogFolderMapping}\"\nDOCKER_UPLOAD_FOLDER_MAPPING=\"${APPHOME}/${prop_dockerUploadFolderMapping}\"\n\n#for port mapping, each time a new container will increate the port no.\n#e.g for mapping 9200:9200, container 1 will have 9200:9200, container 2 will 9201:9200\ni=0\n\nwhile [ $i -le `expr ${prop_dockerContainerCount} - 1` ]\ndo\n  #concatenate each port mapping\n  FINAL_PORT_MAPPING=\"\"\n  \n  for k in ${DOCKER_PORT_MAPPINGS}\n  do\n    SOURCE_PORT=`echo ${k} | awk '{ split($0,array,\":\")} END {print array[1]}'`\n    TARGET_PORT=`echo ${k} | awk '{ split($0,array,\":\")} END {print array[2]}'`\n    FINAL_PORT_MAPPING=\"${FINAL_PORT_MAPPING} -p `expr ${SOURCE_PORT} + ${i}`:${TARGET_PORT}\"\n  done\n  \n  DOCKER_NODE_NAME=\"Node${i}-${HOSTNAME}\"\n  \n  #replace xxx with node name, each node will have seperate data folder/log folder\n  FINAL_LOG_FOLDER_MAPPING=${DOCKER_LOG_FOLDER_MAPPING//nodexxx/${DOCKER_NODE_NAME}}\n  \n  \n  #create the mapping folder if not existing in host \n  # and change folder mode to 777 in case that docker containers cannot write to host folder\n  SOURCE_LOG_FOLDER=`echo ${FINAL_LOG_FOLDER_MAPPING} | awk '{ split($0,array,\":\")} END {print array[1]}'`\n  \n  #create source folder is not existing\n  myexecute \"mkdir -p ${SOURCE_LOG_FOLDER}\"\n  \n  \n  #change mode in case that docker container cannot write data to host folder\n  myexecute \"chmod -R 777 ${SOURCE_LOG_FOLDER}\"\n  \n  \n  \n  mylog \"[INFO] starting new docker container for ${APPNAME} on host <<${HOSTNAME}>>\"\n  myexecute \"docker run \\\n      --net=host \\\n\t  -d \\\n\t  ${FINAL_PORT_MAPPING} \\\n\t  -v ${prop_javaHome}:/opt/apps/java \\\n\t  -v ${DOCKER_CONFIG_FOLDER_MAPPING} \\\n\t  -v ${FINAL_LOG_FOLDER_MAPPING} \\\n\t  -v ${DOCKER_UPLOAD_FOLDER_MAPPING} \\\n\t  ${prop_dockerImageName}:${prop_dockerImageVersion} \\\n     \"\n  \n  \n  #i++\n  i=`expr $i + 1`\n  \n  #sleep to wait server process up\n  myexecute \"sleep ${prop_startOneSleep}\"\n  mylog \"------------------------------------\"\n  mylog \"\"\ndone\n\n\n\n\ncount=`docker ps --no-trunc=true | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} = ${prop_dockerContainerCount} ]; then\n    mylog \"[INFO]  ${prop_dockerContainerCount} docker containers for ${APPNAME} started successfully on server <<${HOSTNAME}>>\"\nelif [ ${count} = 0 ]; then\n\tmylog \"[ERROR] All containers for ${APPNAME} failed to start on server <<${HOSTNAME}>>, yon can check log by /var/lib/docker/containers/xxx/*.log\"\nelse\n    mylog \"[ERROR] ${prop_dockerContainerCount} containers for ${APPNAME} are expected, but only ${count} started on server <<${HOSTNAME}>>, yon can check log by /var/lib/docker/containers/xxx/*.log\"\nfi\n\nexit 0\n\n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/docker/manager/stop.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nmylog \"[INFO] calling stop.sh\"\n\n\nAPPNAME=${prop_package}\nHOSTNAME=`hostname`\nSTOP_TIMEOUT=${prop_stopNodeTimeout}\n\n\nmylog \"[INFO] Stopping containers for  ${APPNAME} on host ${HOSTNAME}\"\n\nPROCESS_ID=`ps -ef | grep \"${prop_dockerProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nisNumber ${PROCESS_ID}\n#$? represents the result of last unix command\nnumberCheck=$?\nif [ numberCheck ]; then\n    #kill -0 will send a signal to the process to check if the process exists, 0 menas exists and 1 vice visa\n    if kill -0 ${PROCESS_ID} > /dev/null 2>&1; then\n      mylog \"[DEBUG]  checked docker daemon is running well on server <<${HOSTNAME}>> with pid: ${PROCESS_ID}\"\n    else\n      mylog \"[ERROR]  docker daemon is not running on server <<${HOSTNAME}>>, pleae start it first\"\n      exit 0\n    fi\nfi\n\n#check nginx container existing or not \ncount=`docker ps | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} != 0 ]; then\n    mylog \"[INFO] checked total ${count} containers for ${APPNAME} are running, gonna stop them\"\n    \n    CONTAINER_IDS=`docker ps | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | awk '{ print $1 }'`\n    \n    for i in $CONTAINER_IDS\n    do\n      mylog \"[INFO]  stopping container id <<${i}>>\"\n      \n      myexecute \"docker stop ${i}\"\n      \n      myexecute \"sleep ${STOP_TIMEOUT}\"\n      \n      #check again if the container is stopped successfully\n      count=`docker ps | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | grep ${i} | wc -l`\n      if [ ${count} != \"0\" ]; then\n      \n        mylog \"[WARN] failed to stop the container <<${i}>>, gonna kill it\"\n        myexecute \"docker kill ${i}\"\n      fi\n      \n    done\nelse\n    mylog \"[INFO] no any container for ${APPNAME} is running, will do nothing\"\n    exit 0;\nfi\n\n\n#check finally\ncount=`docker ps | grep \"${prop_dockerImageName}\" | grep \"${prop_dockerImageVersion}\" | wc -l`\nif [ ${count} != \"0\" ]; then\n\tmylog \"[ERROR] failed to stop/kill all containers for ${APPNAME}, please stop it manually\"\nfi\n\nmylog \"[INFO] all containers for ${APPNAME} are stopped successfully on server <<${HOSTNAME}>>\"\nexit 0\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/common/common-env.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n#SCRIPT_PATH must be defined firstly by calling script\necho \"[INFO] calling common-env.sh\"\nif [ \"${SCRIPT_PATH}\" = \"\" ]; then\n  echo \"[ERROR] SCRIPT_PATH is not defined in calling script\"\n  exit 1\nelse\n    #############\n\t# define own function\n\t#############\n\t\n\t#print out command into console (and log file if there is one) and then execute it\n\tmyexecute () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theCommand=${1}\n\t  echo \"${dt}: [COMMAND] ${theCommand}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: [COMMAND] ${theCommand}\" >> ${LOG}\n\t  fi\n\t  \n\t  ${theCommand}\n\t}\n\t\n\tmyexecute2 () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theCommand=${1}\n\t  echo \"${dt}: [COMMAND] ${theCommand}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: [COMMAND] ${theCommand}\" >> ${LOG}\n\t  fi\n\t  \n\t  eval ${theCommand}\n\t}\n\t\n\t#print out log into console (and log file if there is one)\n\tmylog () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theLog=${1}\n\t  echo \"${dt}: ${theLog}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo \"${dt}: ${theLog}\" >> ${LOG}\n\t  fi\n\t  \n\t}\n\t\n\t#print out log into console (and log file if there is one), and transate \\n into new line\n\tmylog2 () {\n\t  local dt=`date +%Y-%m-%d\\ %H:%M:%S`\n\t  local theLog=${1}\n\t  echo -e \"${dt}: ${theLog}\"\n\t  if [ \"${LOG}\" != \"\" ]; then\n\t    echo -e \"${dt}: ${theLog}\" >> ${LOG}\n\t  fi\n\t  \n\t}\n\t\n\t#check it is a number or not\n\tisNumber () {\n\t  var=${1}\n\t  if [ ${var} -eq ${var} 2> /dev/null ]\n\t  then\n\t    return 0\n\t  else\n\t    return 1\n\t  fi\n    }\n\n\t############\n\t# to export variables\n\t############\n\t\n\t#export all variables in env.properties\n\techo \"[INFO] export all variables in env.properties\"\n\tif [ -f ${SCRIPT_PATH}/../env/env.properties ]; then\n\t  myexecute \"source ${SCRIPT_PATH}/../env/env.properties\"\n\telif [ -f ${SCRIPT_PATH}/../env/env.properties ]; then\n\t  myexecute \"source ${SCRIPT_PATH}/../env/env.properties\"\n\telse\n\t  echo \"[ERROR] cannot find env.properties\"\n\t  exit 1\n\tfi\n\t\nfi\n\n\necho \"[INFO] common-env.sh is done\"\n\n#exit 0 is not allowed here which is stop calling script from going on executing \n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/common/install-cluster.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used for cluster install\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n# The preinstall.sh has been lost.(It is unused.)\nif [ \"${prop_runPreinstall}\" = \"true\" ]; then\n    myexecute \"${SCRIPT_PATH}/preinstall.sh\"\n    if [ $? != 0 ]; then\n      exit 1\n    fi\nfi\n\nmylog \"[INFO] Begin install-cluster.sh\"\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\nAPPROOT=${prop_appRoot}\nAPPNAME=${prop_package}\nAPPHOME=${APPROOT}/${APPNAME}\nHOSTNAME=`hostname`\n\n\nCLUSTER_NODES=${prop_clusterNodes}\n#replace ',' with space\nCLUSTER_NODES=${CLUSTER_NODES//,/ }\n#replace '\"' with null\nCLUSTER_NODES=${CLUSTER_NODES//\\\"/}\n\nMANUAL_FOLDERS=${prop_manualFolders}\nMANUAL_FOLDER_MODE=${prop_manualFolderMode}\n\n\n\nfor i in ${CLUSTER_NODES}\ndo\n  mylog \"\"\n  mylog \"-----------------------------\"\n  mylog \"[INFO] Connecting to host ${i}\"\n  \n  \n  #create app home folder and new version folder\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} mkdir -p ${APPHOME}/${APPVERSION}\"\n  mylog \"[INFO] Folder ${APPHOME}/${APPVERSION} is created successfully on host <<${i}>>\" \n\n  #copy files from current host to another node by scp command\n  #-p preserves modification times, access times, and modes from the original file\n  mylog \"[INFO] copying files to host <<${i}>> by scp command\"\n  myexecute \"scp -rp ${SCRIPT_PATH}/../* root@${i}:${APPHOME}/${APPVERSION}/\"\n  mylog \"[INFO] Copy is done!\"\n  \n  #change owner and group for app package\n  mylog \"[INFO] changing owner and group recursively\"\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} chown -R ${prop_ownerGroup} ${APPHOME}/${APPVERSION}/\"\n  mylog \"[INFO] Owner and group set up done!\"\n  \n  #create manual folders\n  if [ \"${MANUAL_FOLDERS}\" != \"\" ]; then\n      theCommand=\"ssh -oStrictHostKeyChecking=no root@${i} \\\"pwd \"\n      for MANUAL_FOLDER in ${MANUAL_FOLDERS}\n\t  do\n\t      theCommand=\"${theCommand} && mkdir -p ${APPHOME}/${MANUAL_FOLDER}\"\n\t\t  if [ \"${MANUAL_FOLDER_MODE}\" != \"\" ]; then\n\t\t    theCommand=\"${theCommand} && chmod -R ${MANUAL_FOLDER_MODE} ${APPHOME}/${MANUAL_FOLDER}\"\n\t\t  fi\n\t  done\n\t  theCommand=\"${theCommand} \\\" \"\n\t  myexecute2 \"${theCommand}\"\n  fi\n  \n  #create soft link named 'current', -s:soft link -v:debug mode -n:treate link as normal file if it linking to a folder\n  #-f:force create it is already there\n  mylog \"[INFO] Create soft link named 'current'\"\n  myexecute \"ssh -oStrictHostKeyChecking=no root@${i} ln -svnf ${APPHOME}/${APPVERSION} ${APPHOME}/current\"\n  mylog \"[INFO] Link creation is done!\"\n  \n  if [ \"${prop_runPostinstall}\" = \"true\" ]; then\n    myexecute \"ssh -oStrictHostKeyChecking=no root@${i} ${APPHOME}/current/scripts/postinstall.sh\"\n    mylog \"[INFO] postinstall is done on node ${i}\"\n  fi\n\n  mylog \"--------------------------------\"\ndone\n\nmylog \"[INFO] Cluster installation is done successfully, for more detail please check log ${LOG}\"\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/common/install-single.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used for single server install\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\n# The preinstall.sh has been lost.(It is unused.)\nif [ \"${prop_runPreinstall}\" = \"true\" ]; then\n  myexecute \". ${SCRIPT_PATH}/preinstall.sh\"\n  if [ $? != 0 ]; then\n      exit 1\n  fi\nfi\t\n\nmylog \"[INFO] Begin install-single.sh\"\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\n\n\nAPPROOT=${prop_appRoot}\nAPPNAME=${prop_package}\nAPPHOME=${APPROOT}/${APPNAME}\nHOSTNAME=`hostname`\n\n\nSINGLE_NODE=${prop_singleNode}\nMANUAL_FOLDERS=${prop_manualFolders}\nMANUAL_FOLDER_MODE=${prop_manualFolderMode}\n\n\nmylog \"\"\nmylog \"-----------------------------\"\nmylog \"[INFO] Installing on host ${SINGLE_NODE}\"\n\n\n#create app home folder and new version folder\nmyexecute \"mkdir -p ${APPHOME}/${APPVERSION}\"\nmylog \"[INFO] Folder ${APPHOME}/${APPVERSION} is created successfully on host <<${SINGLE_NODE}>>\" \n\n#copy files from current folder to app home folder\n#-p reserve the specified attributes (default: mode,ownership,timestamps)\nmylog \"[INFO] copying files to host <<${SINGLE_NODE}>> by cp command\"\nmyexecute \"cp -rp ${SCRIPT_PATH}/../* ${APPHOME}/${APPVERSION}/\"\nmylog \"[INFO] Copy is done!\"\n\n#change owner and group for app package\nmylog \"[INFO] changing owner and group recursively\"\nmyexecute \"chown -R ${prop_ownerGroup} ${APPHOME}/${APPVERSION}\"\nmylog \"[INFO] Owner and group set up done!\"\n\n#create manual folders\nif [ \"${MANUAL_FOLDERS}\" != \"\" ]; then\n  for MANUAL_FOLDER in ${MANUAL_FOLDERS}\n  do\n\t  myexecute \"mkdir -p ${APPHOME}/${MANUAL_FOLDER}\"\n\t\n\t  if [ \"${MANUAL_FOLDER_MODE}\" != \"\" ]; then\n\t    myexecute \"chmod -R ${MANUAL_FOLDER_MODE} ${APPHOME}/${MANUAL_FOLDER}\"\n\t  fi\n  done\nfi\n\n#create soft link named 'current', -s:soft link -v:debug mode -n:treate link as normal file if it linking to a folder\n#-f:force create it ignoring if it is already there\nmylog \"[INFO] Create soft link named 'current'\"\nmyexecute \"ln -svnf ${APPHOME}/${APPVERSION} ${APPHOME}/current\"\nmylog \"[INFO] Link creation is done!\"\nmylog \"--------------------------------\"\n\nmylog \"[INFO] Installation is done successfully, for more detail please check log ${LOG}\"\nmylog \"------------------------------------\"\nmylog \"------------------------------------\"\n\n# The postinstall.sh has been lost.(It is unused.)\nif [ \"${prop_runPostinstall}\" = \"true\" ]; then\n  myexecute \". ${SCRIPT_PATH}/postinstall.sh\"\nfi\n\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/common/install.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n###############################\n##  used to install package\n###############################\n\n#the path of this script when running\nif cd \"`dirname $0`\"; then\n    export SCRIPT_PATH=${PWD}\n    echo \"[INFO] export SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    exit 1\nfi\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nAPPVERSION=`date +%Y%m%d-%H%M%S`\nLOG=/tmp/install-${prop_package}-${APPVERSION}.log\n\nmylog \"[INFO] Begin install.sh\"\n\n#check it is a single node installation or a cluster installation\nif [ \"${prop_isCluster}\" = \"true\" ]; then\n  mylog \"[INFO] checked you are doing CLUSTER installation\"\n  myexecute \"${SCRIPT_PATH}/install-cluster.sh\"\nelse\n  mylog \"[INFO] checked you are doing SINGLE NODE installation\"\n  myexecute \"${SCRIPT_PATH}/install-single.sh\"\nfi\n\nexit 0\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/common/package.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3\" \n  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 \n  http://maven.apache.org/xsd/assembly-1.1.3.xsd\">\n  \n    <id>0.1</id>\n    <formats>\n        <format>tar</format>\n    </formats>\n      \n    <fileSets>\n      \n        <fileSet>\n            <directory>scripts/${package.format}/manager</directory>\n            <outputDirectory>/scripts</outputDirectory>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>scripts/${package.format}/common</directory>\n            <outputDirectory>/scripts</outputDirectory>\n            <fileMode>0755</fileMode>\n            <includes>\n              <include>install-cluster.sh</include>\n              <include>install-single.sh</include>\n              <include>install.sh</include>\n              <include>common-env.sh</include>\n            </includes>\n        </fileSet>\n        \n        <fileSet>\n            <directory>env/${package.environment}</directory>\n            <outputDirectory>/env</outputDirectory>\n        </fileSet>\n    </fileSets>\n    \n     <files>\n\t\t<file>\n\t\t\t<source>target/${package}-${package.version}.war</source>\n\t\t\t<outputDirectory>/</outputDirectory>\n\t\t\t<destName>${package}-${package.version}.war</destName>\n\t\t\t<fileMode>0755</fileMode>\n\t\t</file>\n\t </files>\n    \n    \n   \n</assembly>"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/manager/setenv.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\necho \"[INFO] calling setenv.sh\"\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n############\n# call common-env.sh\n############\n. ${SCRIPT_PATH}/common-env.sh\n\n\n#other env setup\n#xxx\n#xxx\n\n\necho \"[INFO] setenv.sh is done\"\n\n#exit 0 is not allowed here which will stop calling script from going on executing\n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/manager/start.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nmylog \"[INFO] calling start.sh\"\n\n\nHOSTNAME=`hostname`\nAPPNAME=${prop_package}\nAPPROOT=${prop_appRoot}\nAPPHOME=${APPROOT}/${APPNAME}\nLOG=/tmp/start-${APPNAME}.log\n\n\n#check java home\nJAVA_HOME=${prop_javaHome}\nif [ \"${JAVA_HOME}\" = \"\" ]; then\n    mylog \"[ERROR] JAVA_HOME cannot be null\"\n    exit 1\nelif [ ! -d ${JAVA_HOME} ]; then\n    mylog \"[ERROR] ${JAVA_HOME} does not exist as JAVA_HOME\"\n    exit 1\nfi\n\n\n#check if springboot process is up or not\nPROCESS_ID=`ps -ef | grep java | grep \"${prop_springbootProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nif [ ${PROCESS_ID} ]; then\n  mylog \"[WARN] ${APPNAME} is already running with process id ${PROCESS_ID} on server <<${HOSTNAME}>>\"\n  exit 0\nelse\n  mylog \"[INFO] checked no ${APPNAME} running process on server <<${HOSTNAME}>>, will start it\"\nfi\n\n#start up new process\nspringbootExecutableWar=${APPHOME}/current/${prop_springbootWarName}-${prop_springbootWarVersion}.war\nmyexecute2 \"nohup ${JAVA_HOME}/bin/java -jar  ${springbootExecutableWar} --spring.config.location=${APPHOME}/current/env/application.properties >/dev/null 2>&1 &\"\n\nmyexecute2 \"sleep ${prop_startOneSleep}\"\nPROCESS_ID=`ps -ef | grep java | grep \"${prop_springbootProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nif [ ${PROCESS_ID} ]; then\n  mylog \"[INFO] ${APPNAME} started successfully with process id ${PROCESS_ID} on server <<${HOSTNAME}>>\"\nelse\n  mylog \"[ERROR] ${APPNAME} failed to start up on server <<${HOSTNAME}>>, you can check log ${LOG}\"\nfi\n\nexit 0\n\n\n\n\n\n"
  },
  {
    "path": "springboot-mybatis/scripts/springboot/manager/stop.sh",
    "content": "#ident  \"%W%\"\n#!/bin/sh -x\n\n\n#find out the absolute path of the script when being executed\nif cd \"`dirname $0`\"; then\n    SCRIPT_PATH=${PWD}\n    echo \"[INFO] SCRIPT_PATH=${SCRIPT_PATH}\"\n    cd \"${OLDPWD}\" || exit 1\nelse\n    echo \"[ERROR] cannot find script folder path\"\n    exit 1\nfi\n\n\n\n#call setenv\n. ${SCRIPT_PATH}/setenv.sh\n\n\nmylog \"[INFO] calling stop.sh\"\n\n\nAPPNAME=${prop_package}\nHOSTNAME=`hostname`\nSTOP_TIMEOUT=${prop_stopNodeTimeout}\n\n\nmylog \"[INFO] Stopping ${APPNAME} on host ${HOSTNAME}\"\n\n#check if springboot process is up or not\nPROCESS_ID=`ps -ef | grep java | grep \"${prop_springbootProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nif [ ${PROCESS_ID} ]; then\n  mylog \"[INFO] found running ${APPNAME} process with id = ${PROCESS_ID} on server <<${HOSTNAME}>>, will stop it\"\n  #stop running process\n  myexecute2 \"kill -9 ${PROCESS_ID}\"\n  myexecute2 \"sleep ${prop_stopNodeTimeout}\"\nelse\n  mylog \"[WARN] no running ${APPNAME} process on server <<${HOSTNAME}>>\"\n  exit 0\nfi\n\n#check again\nPROCESS_ID=`ps -ef | grep java | grep \"${prop_springbootProcessKeyWord}\" | grep -v grep | awk '{ print $2 }'`\nif [ ${PROCESS_ID} ]; then\n  mylog \"[ERROR] failed to stop running ${APPNAME} process with id = ${PROCESS_ID} on server <<${HOSTNAME}>>, you can check log ${LOG}\"\n  exit 1\nelse\n  mylog \"[INFO] ${APPNAME} is stopped successfully on server <<${HOSTNAME}>>\"\nfi\n\nexit 0\n\n\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\nimport static org.springframework.boot.SpringApplication.*;\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example,com.jf\")\n@SpringBootApplication\n@EnableScheduling\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/bean/User.java",
    "content": "package com.us.example.bean;\nimport java.util.Date;\npublic class User  {\n    private Integer id;\n    /** The name. */\n    private String name;\n\n    /** The password. */\n    private String password;\n    /** The rePassword. */\n    private String rePassword;\n\n    /** The username. */\n    private String username;\n\n    /** The division id. */\n    private Integer divisionId;\n\n    /** The email. */\n    private String email;\n\n    /** The gender. */\n    private String gender;\n\n    /** The mobilephone. */\n    private String mobilephone;\n\n    /** The telephone. */\n    private String telephone;\n\n    /** The user type. */\n    private Integer userType;\n\n    /** The create by. */\n    private String createBy;\n\n    /** The create time. */\n    private Date createTime;\n\n    /** The update by. */\n    private String updateBy;\n\n    /** The update time. */\n    private Date updateTime;\n\n    /** The disabled. */\n    private Integer disabled;\n\n    /** The theme. */\n    private String theme;\n\n    /** The is ldap. */\n    private Integer isLdap;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * Get the name.\n     *\n     * @return the name\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Set the name.\n     *\n     * @param name the name\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * Get the re password.\n     *\n     * @return the re password\n     */\n    public String getRePassword()\n    {\n        return rePassword;\n    }\n\n    /**\n     * Set the re password.\n     *\n     * @param rePassword the re password\n     */\n    public void setRePassword(String rePassword)\n    {\n        this.rePassword = rePassword;\n    }\n\n    /**\n     * Get the password.\n     *\n     * @return the password\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Set the password.\n     *\n     * @param password the password\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * Get the username.\n     *\n     * @return the username\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * Set the username.\n     *\n     * @param username the username\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * Get the division id.\n     *\n     * @return the division id\n     */\n    public Integer getDivisionId() {\n        return divisionId;\n    }\n\n    /**\n     * Set the division id.\n     *\n     * @param divisionId the division id\n     */\n    public void setDivisionId(Integer divisionId) {\n        this.divisionId = divisionId;\n    }\n\n    /**\n     * Get the email.\n     *\n     * @return the email\n     */\n    public String getEmail() {\n        return email;\n    }\n\n    /**\n     * Set the email.\n     *\n     * @param email the email\n     */\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    /**\n     * Get the gender.\n     *\n     * @return the gender\n     */\n    public String getGender() {\n        return gender;\n    }\n\n    /**\n     * Set the gender.\n     *\n     * @param gender the gender\n     */\n    public void setGender(String gender) {\n        this.gender = gender;\n    }\n\n    /**\n     * Get the mobilephone.\n     *\n     * @return the mobilephone\n     */\n    public String getMobilephone() {\n        return mobilephone;\n    }\n\n    /**\n     * Set the mobilephone.\n     *\n     * @param mobilephone the mobilephone\n     */\n    public void setMobilephone(String mobilephone) {\n        this.mobilephone = mobilephone;\n    }\n\n    /**\n     * Get the telephone.\n     *\n     * @return the telephone\n     */\n    public String getTelephone() {\n        return telephone;\n    }\n\n    /**\n     * Set the telephone.\n     *\n     * @param telephone the telephone\n     */\n    public void setTelephone(String telephone) {\n        this.telephone = telephone;\n    }\n\n    /**\n     * Get the user type.\n     *\n     * @return the user type\n     */\n    public Integer getUserType() {\n        return userType;\n    }\n\n    /**\n     * Set the user type.\n     *\n     * @param userType the user type\n     */\n    public void setUserType(Integer userType) {\n        this.userType = userType;\n    }\n\n    /**\n     * Get the creates the by.\n     *\n     * @return the creates the by\n     */\n    public String getCreateBy() {\n        return createBy;\n    }\n\n    /**\n     * Set the creates the by.\n     *\n     * @param createBy the creates the by\n     */\n    public void setCreateBy(String createBy) {\n        this.createBy = createBy;\n    }\n\n    /**\n     * Get the creates the time.\n     *\n     * @return the creates the time\n     */\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    /**\n     * Set the creates the time.\n     *\n     * @param createTime the creates the time\n     */\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    /**\n     * Get the update by.\n     *\n     * @return the update by\n     */\n    public String getUpdateBy() {\n        return updateBy;\n    }\n\n    /**\n     * Set the update by.\n     *\n     * @param updateBy the update by\n     */\n    public void setUpdateBy(String updateBy) {\n        this.updateBy = updateBy;\n    }\n\n    /**\n     * Get the update time.\n     *\n     * @return the update time\n     */\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    /**\n     * Set the update time.\n     *\n     * @param updateTime the update time\n     */\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n\n    /**\n     * Get the disabled.\n     *\n     * @return the disabled\n     */\n    public Integer getDisabled() {\n        return disabled;\n    }\n\n    /**\n     * Set the disabled.\n     *\n     * @param disabled the disabled\n     */\n    public void setDisabled(Integer disabled) {\n        this.disabled = disabled;\n    }\n\n    /**\n     * Get the theme.\n     *\n     * @return the theme\n     */\n    public String getTheme() {\n        return theme;\n    }\n\n    /**\n     * Set the theme.\n     *\n     * @param theme theme\n     */\n    public void setTheme(String theme) {\n        this.theme = theme;\n    }\n\n    /**\n     * Get the checks if is ldap.\n     *\n     * @return the checks if is ldap\n     */\n    public Integer getIsLdap()\n    {\n        return isLdap;\n    }\n\n    /**\n     * Set the checks if is ldap.\n     *\n     * @param isLdap the checks if is ldap\n     */\n    public void setIsLdap(Integer isLdap)\n    {\n        this.isLdap = isLdap;\n    }\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/config/DBConfig.java",
    "content": "package com.us.example.config;\n\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/config/MyBatisConfig.java",
    "content": "package com.us.example.config;\nimport javax.sql.DataSource;\n\nimport com.jf.page.interceptor.PageInterceptor;\nimport org.apache.ibatis.plugin.Interceptor;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@ComponentScan\npublic class MyBatisConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"sqlSessionFactory\")\n    public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {\n        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n        sessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n        return sessionFactory;\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/config/MyBatisScannerConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/config/TransactionConfig.java",
    "content": "package com.us.example.config;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/controller/UserController.java",
    "content": "package com.us.example.controller;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.us.example.service.UserService;\nimport com.us.example.util.CommonUtil;\n\n/**\n *\n * @ClassName UserController\n * @author abel\n * @date 2016年11月10日\n */\n@Controller\n@RequestMapping(value = \"/users\")\npublic class UserController {\n    private static final Logger logger = Logger.getLogger(UserController.class);\n\n    @Autowired\n    private UserService userService;\n\n\n    /***\n     * api :localhost:8099/users?id=99\n     *  http://localhost:8099/users?limit=2&page=2\n     * @param request\n     * @return\n     */\n    @RequestMapping(method = RequestMethod.GET, produces = \"application/json;charset=UTF-8\")\n    @ResponseBody\n    public ResponseEntity<Object> list(HttpServletRequest request) {\n        Map<String, Object> map = CommonUtil.getParameterMap(request);\n        return new ResponseEntity<>(userService.getList(map), HttpStatus.OK);\n    }\n\n\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/dao/UserDao.java",
    "content": "package com.us.example.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.us.example.bean.User;\n\npublic interface UserDao {\n     List<User> getList(Map<String,Object> map);\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/service/Impl/UserServiceImpl.java",
    "content": "package com.us.example.service.Impl;\n\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport com.jf.page.annotation.Page;\nimport javafx.scene.input.DataFormat;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Service;\n\nimport com.us.example.dao.UserDao;\n\nimport com.us.example.service.UserService;\n\n/**\n *\n * @ClassName UserServiceImpl\n * @author abel\n * @date 2016年11月10日\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\n    @Autowired\n    private UserDao userDao;\n\n    /**\n     *\n     * @param map\n     * @return\n     */\n    @Page\n    @Override\n    public Object getList(Map<String, Object> map) {\n        return userDao.getList(map);\n    }\n\n    //每一秒调用一次  -- 用于测试\n    @Scheduled(cron = \"0/30 * * * * ?\")\n    @Override\n    public void printName() {\n        System.out.println(new Date());\n        System.out.println(\"my name is yang \");\n    }\n\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/service/UserService.java",
    "content": "package com.us.example.service;\n\nimport java.util.Map;\n\nimport com.us.example.bean.User;\n\n/**\n * The Interface UserService.\n */\npublic interface UserService {\n\n    /**\n     * Gets the list.\n     *\n     * @param map the map\n     * @return the list\n     */\n    Object getList(Map<String, Object> map);\n\n    void printName();\n\n}"
  },
  {
    "path": "springboot-mybatis/src/main/java/com/us/example/util/CommonUtil.java",
    "content": "package com.us.example.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang3.StringUtils;\n\n\n\npublic  class CommonUtil {\n\n    /**\n     * 从request中获得参数Map，并返回可读的Map.\n     *\n     * @param request the request\n     * @return the parameter map\n     */\n    public static Map<String, Object> getParameterMap(HttpServletRequest request) {\n        // 参数Map\n        Map<String, String[]> properties = request.getParameterMap();\n        //返回值Map\n        Map<String, Object> returnMap = new HashMap<String, Object>();\n        Set<String> keySet = properties.keySet();\n        for(String key: keySet){\n            String[] values = properties.get(key);\n            String value = \"\";\n            if(values != null && (values.length==1&&StringUtils.isNotBlank(values[0]))?true:false){\n                for(int i=0;i<values.length;i++){\n                    if(values[i] != null && !\"\".equals(values[i])){\n//\t\t\t\t\t\t\tvalue = new String(values[i].getBytes(\"ISO-8859-1\"),\"UTF-8\") + \",\";\n                        value += values[i] + \",\";\n                    }\n                }\n                if(value != null && !\"\".equals(value)){\n                    value = value.substring(0, value.length()-1);\n                }\n                if(key.equals(\"keywords\")){//关键字特殊查询字符转义\n                    value =  value.replace(\"_\", \"\\\\_\").replace(\"%\", \"\\\\%\");\n                }\n                returnMap.put(key, value);\n            }\n        }\n        return returnMap;\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.UserDao\">\n\t<resultMap id=\"userMap\" type=\"com.us.example.bean.User\">\n\t\t<id property=\"id\" column=\"ID\" />\n\t\t<result property=\"name\" column=\"NAME\" />\n\t\t<result property=\"password\" column=\"PASSWORD\" />\n\t\t<result property=\"username\" column=\"USERNAME\" />\n\t\t<result property=\"divisionId\" column=\"DIVISION_ID\" />\n\t\t<result property=\"email\" column=\"EMAIL\" />\n\t\t<result property=\"gender\" column=\"GENDER\" />\n\t\t<result property=\"mobilephone\" column=\"MOBILEPHONE\" />\n\t\t<result property=\"telephone\" column=\"TELEPHONE\" />\n\t\t<result property=\"userType\" column=\"USER_TYPE\" />\n\t\t<result property=\"createBy\" column=\"CREATE_BY\" />\n\t\t<result property=\"createTime\" column=\"CREATE_TIME\" />\n\t\t<result property=\"updateBy\" column=\"UPDATE_BY\" />\n\t\t<result property=\"updateTime\" column=\"UPDATE_TIME\" />\n\t\t<result property=\"disabled\" column=\"DISABLED\" />\n\t\t<result property=\"theme\" column=\"THEME\" />\n\t\t<result property=\"isLdap\" column=\"IS_LDAP\" />\n\n\t</resultMap>\n\n\t<sql id=\"queryCondition\">\n\t\t<where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand ID = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand NAME = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"password != null and password != ''\">\n\t\t\t\tand PASSWORD = #{password}\n\t\t\t</if>\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tand USERNAME = #{username}\n\t\t\t</if>\n\t\t\t<if test=\"divisionId != null and divisionId != ''\">\n\t\t\t\tand DIVISION_ID = #{divisionId}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand EMAIL = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"gender != null and gender != ''\">\n\t\t\t\tand GENDER = #{gender}\n\t\t\t</if>\n\t\t\t<if test=\"mobilephone != null and mobilephone != ''\">\n\t\t\t\tand MOBILEPHONE = #{mobilephone}\n\t\t\t</if>\n\t\t\t<if test=\"telephone != null and telephone != ''\">\n\t\t\t\tand TELEPHONE = #{telephone}\n\t\t\t</if>\n\t\t\t<if test=\"userType != null and userType != ''\">\n\t\t\t\tand USER_TYPE = #{userType}\n\t\t\t</if>\n\t\t\t<if test=\"disabled != null and disabled != ''\">\n\t\t\t\tand DISABLED = #{disabled}\n\t\t\t</if>\n\t\t\t<if test=\"theme != null and theme != ''\">\n\t\t\t\tand THEME = #{theme}\n\t\t\t</if>\n\t\t\t<if test=\"keywords != null and keywords != ''\">\n\t\t\t\tand (name like CONCAT('%', #{keywords},'%') OR username\n\t\t\t\tlike CONCAT('%', #{keywords},'%')\n\t\t\t\tOR telephone like CONCAT('%', #{keywords},'%') OR email like\n\t\t\t\tCONCAT('%', #{keywords},'%') )\n\t\t\t</if>\n\n\t\t</where>\n\t</sql>\n\t<select id=\"getList\" parameterType=\"map\" resultMap=\"userMap\">\n\t\tSELECT * FROM sec_user\n\t\t<include refid=\"queryCondition\" />\n\t\torder by create_time desc\n\t</select>\n</mapper>"
  },
  {
    "path": "springboot-mybatis/src/test/java/com/us/example/BaseTest.java",
    "content": "package com.us.example;\n\nimport com.us.example.config.DBConfig;\nimport com.us.example.config.MyBatisConfig;\nimport com.us.example.config.MyBatisScannerConfig;\nimport org.junit.Assert;\nimport org.junit.runner.RunWith;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Created by yangyibo on 17/2/10.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {BaseTest.ComponentScanConfig.class, DBConfig.class, MyBatisScannerConfig.class, MyBatisConfig.class})\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest extends AbstractTransactionalJUnit4SpringContextTests {\n    @Configuration\n    @ComponentScan(basePackages = {\"com.us.example\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n    public void assertNotNull(Object obj) {\n        System.out.println(obj);\n        Assert.assertNotNull(obj);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/src/test/java/com/us/example/service/UserServiceTest.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.BaseTest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by yangyibo on 17/2/10.\n */\npublic class UserServiceTest extends BaseTest {\n    @Autowired\n    UserService userService;\n\n    @Test\n    public void getListTest() {\n        Map<String, Object> map = new HashMap();\n        map.put(\"id\", 1);\n        userService.getList(map);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/tar-it.sh",
    "content": "#!/bin/bash\n\n\n\n################################\n# based on maven assembly plugin\n\n\n\nenvironment=$1\npackage=$2\npackageVersion=$3\npackageFormat=$4\n\nif [ \"${environment}\" = \"\" ]; then\n    echo [ERROR] \"Please provide env as first param\"\n    exit 1\nfi\n\nif [ \"${package}\" = \"\" ]; then\n    echo [ERROR] \"Please provide package name as second param\"\n    exit 1\nfi\n\nif [ \"${packageVersion}\" = \"\" ]; then\n    echo [ERROR] \"Please provide version as third param\"\n    exit 1\nfi\n\nif [ \"${packageFormat}\" = \"\" ]; then\n    echo [ERROR] \"Please provide package format as forth param\"\n    exit 1\nfi\n\n\ntheCommand=\"mvn -e assembly:single -Dpackage=${package} -Dpackage.version=${packageVersion} -Dpackage.environment=${environment} -Dpackage.format=${packageFormat}\"\necho ${theCommand}\n${theCommand}\n\n"
  },
  {
    "path": "springboot-mybatis/war-it.sh",
    "content": "#!/bin/sh\n\n\n# the java must be goal .I think it may be not very good. （Sean 20170216）\nCOUNT=`java -version 2>&1 | grep 'java version' | grep 1.8 |  grep -v grep | wc -l`\nif [ ${COUNT} != 1 ]; then\n  COUNT=`echo $JAVA_HOME | grep 1.8 |  grep -v grep | wc -l`\n  if [ ${COUNT} != 1 ]; then\n    echo [ERROR] \"Cannot find java 8\"\n    exit 1\n  fi\nfi\n\n\npackage=$1\nversion=$2\nenv=$3\nresources=$4\n\nif [ \"${package}\" = \"\" ]; then\n    echo [ERROR] \"Please provide package name as first param\"\n    exit 1\nfi\n\nif [ \"${version}\" = \"\" ]; then\n    echo [ERROR] \"Please provide package version as second param\"\n    exit 1\nfi\n\nif [ \"${env}\" = \"\" ]; then\n    echo [ERROR] \"Please provide env as third param\"\n    exit 1\nfi\n\n#在pom.xml文件里面定义的 maven的参数 详细请看 maven -D 命令的含义\n#-X To debug the command.\ntheCommand=\"mvn clean package -Dpackage=${package} -Dpackage.version=${version} -Dpackage.environment=${env} -Dpackage.resources=${resources} \"\necho [INFO] ${theCommand}\nexec ${theCommand}\n\n\n\n"
  },
  {
    "path": "springboot-mybatis2/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-mybatis2</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.40</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-mybatis2/sql/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50719\n Source Host           : 127.0.0.1\n Source Database       : oldMan\n\n Target Server Type    : MySQL\n Target Server Version : 50719\n File Encoding         : utf-8\n\n Date: 04/02/2019 15:27:32 PM\n*/\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n--  Table structure for `user`\n-- ----------------------------\nDROP TABLE IF EXISTS `user`;\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` varchar(100) DEFAULT NULL,\n  `address` varchar(200) DEFAULT NULL,\n  `mobile` varchar(50) DEFAULT NULL,\n  `email` varchar(100) DEFAULT NULL,\n  `create_time` datetime DEFAULT NULL,\n  `role` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "springboot-mybatis2/src/main/java/cn/abel/Application.java",
    "content": "package cn.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/3/26\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis2/src/main/java/cn/abel/bean/User.java",
    "content": "package cn.abel.bean;\n\nimport java.util.Date;\n\n\npublic class User {\n    private Integer id;\n    private String name;\n    private String address;\n    private String mobile;\n    private String email;\n    private Date createTime;\n    private Integer role;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public Integer getRole() {\n        return role;\n    }\n\n    public void setRole(Integer role) {\n        this.role = role;\n    }\n}"
  },
  {
    "path": "springboot-mybatis2/src/main/java/cn/abel/dao/UserDao.java",
    "content": "package cn.abel.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport cn.abel.bean.User;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\n\n@Repository\n@Mapper\npublic interface UserDao {\n\n    List<User> getByMap(Map<String, Object> map);\n\n    User getById(Integer id);\n\n    Integer create(User user);\n\n    int update(User user);\n\n    int delete(Integer id);\n}"
  },
  {
    "path": "springboot-mybatis2/src/main/java/cn/abel/service/UserService.java",
    "content": "package cn.abel.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport cn.abel.dao.UserDao;\nimport cn.abel.bean.User;\n\n@Service\npublic class UserService {\n    @Autowired\n\tprivate UserDao userDao;\n\t\n\tpublic List<User> getByMap(Map<String,Object> map){\n\t\treturn userDao.getByMap(map);\n\t}\n\t\n\tpublic User getById(Integer id){\n\t\treturn userDao.getById(id);\n\t}\n\t\n\tpublic User create(User user){\n\t\tuserDao.create(user);\n\t\treturn user;\n\t}\n\t\n\tpublic User update(User user){\n\t\tuserDao.update(user);\n\t\treturn user;\n\t}\n\t\n\tpublic int delete(Integer id){\n\t\treturn userDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-mybatis2/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=8009\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.risk.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200  \nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-mybatis2\napplication.main=cn.abel.Application\n\n## LOG\nlogging.file=./logs/springboot-mybatis2.log\n\n\n## \\u4E3B\\u6570\\u636E\\u6E90\\uFF0C\\u9ED8\\u8BA4\\u7684\nspring.datasource.url=jdbc:mysql://localhost:3306/oldMan?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=admin\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\n#\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.datasource.min-idle=5\n#\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\u91CF\nspring.datasource.max-active=100\n#\\u68C0\\u6D4B\\u6570\\u636E\\u5E93\\u7684\\u67E5\\u8BE2\\u8BED\\u53E5\nspring.datasource.validation-query=select 1 from dual\n#\\u7B49\\u5F85\\u8FDE\\u63A5\\u6C60\\u5206\\u914D\\u8FDE\\u63A5\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.connection-timeout=60000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5\\u7684\\u751F\\u547D\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.max-left-time=60000\n#\\u751F\\u6548\\u8D85\\u65F6\nspring.datasource.validation-time-out=3000\n#\\u4E00\\u4E2A\\u8FDE\\u63A5idle\\u72B6\\u6001\\u7684\\u6700\\u5927\\u65F6\\u957F\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.datasource.idle-time-out=60000\n#\\u8BBE\\u7F6E\\u9ED8\\u8BA4\\u5B57\\u7B26\\u96C6\nspring.datasource.connection-init-sql= set names utf8mb4\n\nlogging.level.cn.abel.dao=debug\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\nsmybatis.type-aliases-package=cn.abel.bean\n#Mapper.xml\\u6240\\u5728\\u7684\\u4F4D\\u7F6E\n\n## pagehelper\npagehelper.helperDialect=mysql\npagehelper.reasonable=true\npagehelper.supportMethodsArguments=true\npagehelper.params=count=countSql\n\n\n"
  },
  {
    "path": "springboot-mybatis2/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-mybatis2/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>abel_user</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-mybatis2/src/main/resources/mapper/NewsDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.dao.NewsDao\">\n    <resultMap id=\"newsMap\" type=\"cn.abel.bean.News\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"title\" column=\"title\"/>\n\t\t<result property=\"content\" column=\"content\"/>\n\t\t<result property=\"imagePath\" column=\"image_path\"/>\n\t\t<result property=\"readSum\" column=\"read_sum\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"title != null and title != ''\">\n\t\t\t\tand title = #{title}\n\t\t\t</if>\n\t\t\t<if test=\"content != null and content != ''\">\n\t\t\t\tand content = #{content}\n\t\t\t</if>\n\t\t\t<if test=\"imagePath != null and imagePath != ''\">\n\t\t\t\tand image_path = #{imagePath}\n\t\t\t</if>\n\t\t\t<if test=\"readSum != null and readSum != ''\">\n\t\t\t\tand read_sum = #{readSum}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"newsMap\">\n    \tSELECT * FROM news\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"newsMap\">\n    \tSELECT * FROM news WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.bean.News\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO news(\n\t\t\tid,\n\t\t\ttitle,\n\t\t\tcontent,\n\t\t\timage_path,\n\t\t\tread_sum\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{title},\n\t\t\t#{content},\n\t\t\t#{imagePath},\n\t\t\t#{readSum}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.bean.News\">\n\t\tUPDATE news SET\n\t\t\ttitle = #{title},\n\t\t\tcontent = #{content},\n\t\t\timage_path = #{imagePath},\n\t\t\tread_sum = #{readSum}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM news WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-mybatis2/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"cn.abel.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"cn.abel.bean.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"address\" column=\"address\"/>\n\t\t<result property=\"mobile\" column=\"mobile\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"createTime\" column=\"create_time\"/>\n\t\t<result property=\"role\" column=\"role\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"address != null and address != ''\">\n\t\t\t\tand address = #{address}\n\t\t\t</if>\n\t\t\t<if test=\"mobile != null and mobile != ''\">\n\t\t\t\tand mobile = #{mobile}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"role != null and role != ''\">\n\t\t\t\tand role = #{role}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT * FROM user\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"cn.abel.bean.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tname,\n\t\t\taddress,\n\t\t\tmobile,\n\t\t\temail,\n\t\t\tcreate_time,\n\t\t\trole\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{address},\n\t\t\t#{mobile},\n\t\t\t#{email},\n\t\t\tNOW(),\n\t\t\t#{role}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"cn.abel.bean.User\">\n\t\tUPDATE user SET\n\t\t\tname = #{name},\n\t\t\taddress = #{address},\n\t\t\tmobile = #{mobile},\n\t\t\temail = #{email},\n\t\t\trole = #{role}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-mybatis2/src/test/java/cn/abel/BaseTest.java",
    "content": "package cn.abel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest {\n\n    @Configuration\n    @ComponentScan(basePackages = {\"cn.abel\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n\n    @Test\n    public void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "springboot-mybatis2/src/test/java/cn/abel/service/ServiceTest.java",
    "content": "package cn.abel.service;\n\nimport cn.abel.BaseTest;\nimport cn.abel.bean.User;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\npublic class ServiceTest extends BaseTest {\n\n\n    @Autowired\n    private UserService userService;\n\n    @Test\n    public void dynamicDataSourceTest() throws Exception {\n        List<User> userList = userService.getByMap(null);\n        System.out.println(\"--userList---\" + userList.size());\n\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-neo4j</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.40</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.40</version>\n        </dependency>\n\n        <!--neo4j-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-neo4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>neo4j-ogm-http-driver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/Application.java",
    "content": "package cn.abel.neo4j;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\n\n/**\n * @author yyb\n * @time 2019/3/26\n */\n@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/bean/King.java",
    "content": "package cn.abel.neo4j.bean;\n\n\nimport cn.abel.neo4j.bean.relation.FatherAndSonRelation;\nimport org.neo4j.ogm.annotation.NodeEntity;\nimport org.neo4j.ogm.annotation.Relationship;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 皇帝\n *\n * @author yyb\n * @time 2020/3/23\n */\n@NodeEntity(label = \"King\")\npublic class King extends Person implements Serializable {\n\n    /**\n     * 名字\n     */\n    private String name;\n    /**\n     * 家系：家族关系\n     */\n    private String clan;\n    /**\n     * 年号：生活的时代\n     */\n    private String times;\n    /**\n     * 谥号：人死之后，后人给予评价\n     */\n    private String posthumousTitle;\n    /**\n     * 庙号：君主于庙中被供奉时所称呼的名号\n     */\n    private String TempleNumber;\n    /**\n     * 陵墓\n     */\n    private String tomb;\n    /**\n     * 大事件\n     */\n    private String remark;\n\n    @Relationship(type = \"传位\")\n    King successor;\n\n    /**\n     * 第二种保存关系的方式\n     */\n    @Relationship\n    List<FatherAndSonRelation> sons;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getClan() {\n        return clan;\n    }\n\n    public void setClan(String clan) {\n        this.clan = clan;\n    }\n\n    public String getTimes() {\n        return times;\n    }\n\n    public void setTimes(String times) {\n        this.times = times;\n    }\n\n    public String getPosthumousTitle() {\n        return posthumousTitle;\n    }\n\n    public void setPosthumousTitle(String posthumousTitle) {\n        this.posthumousTitle = posthumousTitle;\n    }\n\n    public String getTempleNumber() {\n        return TempleNumber;\n    }\n\n    public void setTempleNumber(String templeNumber) {\n        TempleNumber = templeNumber;\n    }\n\n    public String getTomb() {\n        return tomb;\n    }\n\n    public void setTomb(String tomb) {\n        this.tomb = tomb;\n    }\n\n    public String getRemark() {\n        return remark;\n    }\n\n    public void setRemark(String remark) {\n        this.remark = remark;\n    }\n\n    public King getSuccessor() {\n        return successor;\n    }\n\n    public void setSuccessor(King successor) {\n        this.successor = successor;\n    }\n\n    public List<FatherAndSonRelation> getSons() {\n        return sons;\n    }\n\n    public void setSons(List<FatherAndSonRelation> sons) {\n        this.sons = sons;\n    }\n\n    /**\n     * 添加友谊的关系\n     * @param\n     */\n    public void addRelation(FatherAndSonRelation fatherAndSonRelation){\n        if(this.sons == null){\n            this.sons = new ArrayList<>();\n        }\n        this.sons.add(fatherAndSonRelation);\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/bean/Person.java",
    "content": "package cn.abel.neo4j.bean;\n\nimport org.neo4j.ogm.annotation.GeneratedValue;\nimport org.neo4j.ogm.annotation.Id;\nimport org.neo4j.ogm.annotation.Index;\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\npublic class Person {\n\n    @Id\n//    @GeneratedValue 该注解应去除否则插入不成功\n    @Index\n    private long id;\n\n    public long getId() {\n        return id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/bean/Queen.java",
    "content": "package cn.abel.neo4j.bean;\n\nimport org.neo4j.ogm.annotation.Relationship;\n\n/**\n * 皇后\n *\n * @author yyb\n * @time 2020/3/23\n */\npublic class Queen extends Person {\n    /**\n     * 名字\n     */\n    private String name;\n    /**\n     * 家系：家族关系\n     */\n    private String clan;\n    /**\n     * 年号：生活的时代\n     */\n    private String times;\n    /**\n     * 庙号：君主于庙中被供奉时所称呼的名号\n     */\n    private String TempleNumber;\n    /**\n     * 谥号：人死之后，后人给予评价\n     */\n    private String posthumousTitle;\n    /**\n     * 陵墓\n     */\n    private String son;\n    /**\n     * 备注\n     */\n    private String remark;\n\n    /**\n     * 关系指向自己\n     */\n    @Relationship(type = \"皇后\", direction = Relationship.INCOMING)\n    private King king;\n\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getClan() {\n        return clan;\n    }\n\n    public void setClan(String clan) {\n        this.clan = clan;\n    }\n\n    public String getTimes() {\n        return times;\n    }\n\n    public void setTimes(String times) {\n        this.times = times;\n    }\n\n    public String getTempleNumber() {\n        return TempleNumber;\n    }\n\n    public void setTempleNumber(String templeNumber) {\n        TempleNumber = templeNumber;\n    }\n\n    public String getPosthumousTitle() {\n        return posthumousTitle;\n    }\n\n    public void setPosthumousTitle(String posthumousTitle) {\n        this.posthumousTitle = posthumousTitle;\n    }\n\n    public String getSon() {\n        return son;\n    }\n\n    public void setSon(String son) {\n        this.son = son;\n    }\n\n    public String getRemark() {\n        return remark;\n    }\n\n    public void setRemark(String remark) {\n        this.remark = remark;\n    }\n\n    public King getKing() {\n        return king;\n    }\n\n    public void setKing(King king) {\n        this.king = king;\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/bean/relation/FatherAndSonRelation.java",
    "content": "package cn.abel.neo4j.bean.relation;\n\nimport cn.abel.neo4j.bean.King;\nimport org.neo4j.ogm.annotation.EndNode;\nimport org.neo4j.ogm.annotation.Id;\nimport org.neo4j.ogm.annotation.RelationshipEntity;\nimport org.neo4j.ogm.annotation.StartNode;\n\n/**\n * 父子关系实体\n * @author yyb\n * @time 2020/3/24\n */\n@RelationshipEntity(type = \"father_son\")\npublic class FatherAndSonRelation {\n\n    @Id\n    private long id;\n\n    @StartNode\n    private King from;\n\n    @EndNode\n    private King to;\n\n    public long getId() {\n        return id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public King getFrom() {\n        return from;\n    }\n\n    public void setFrom(King from) {\n        this.from = from;\n    }\n\n    public King getTo() {\n        return to;\n    }\n\n    public void setTo(King to) {\n        this.to = to;\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/controller/KingController.java",
    "content": "package cn.abel.neo4j.controller;\n\n\nimport cn.abel.neo4j.bean.King;\nimport cn.abel.neo4j.service.KingService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\n@Controller\n@RequestMapping(\"/king\")\npublic class KingController {\n\n    @Autowired\n    private KingService kingService;\n    @RequestMapping(value = \"/save/{id}\", method = RequestMethod.GET)\n    @ResponseBody\n    public String save(@PathVariable long id){\n        List<King> kingList = new ArrayList<>();\n        King king = new King();\n        king.setId(id);\n        king.setName(\"朱元璋\");\n        king.setClan(\"创业者\");\n        king.setPosthumousTitle(\"高皇帝\");\n        king.setTimes(\"洪武（1368年——1398年）\");\n        king.setTempleNumber(\"太祖\");\n        king.setTomb(\"孝陵\");\n        king.setRemark(\"空印案，胡惟庸案\");\n        kingList.add(king);\n        kingService.saveKing(kingList);\n        return \"ok\";\n    }\n\n\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/dao/KingDao.java",
    "content": "package cn.abel.neo4j.dao;\n\nimport cn.abel.neo4j.bean.King;\nimport org.springframework.data.neo4j.annotation.Query;\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\n\n/**\n * 使用Springboot - data - neo4j 生成\n *\n * @author yyb\n * @time 2020/3/23\n */\n@Repository\n@Transactional(rollbackFor = Exception.class)\npublic interface KingDao extends Neo4jRepository<King, Long> {\n\n    /**\n     * 通过名字查找King\n     *\n     * @param name\n     * @return\n     */\n    King findByName(String name);\n\n\n    /**\n     * 获取当前节点下的所有king\n     *\n     * @param name\n     * @return\n     */\n    @Query(\"match p=(a:King)-[r:`传位`*0..]->(b:King) where a.name={0} return p\")\n    List<King> getKings(String name);\n\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/dao/Neo4jDao.java",
    "content": "package cn.abel.neo4j.dao;\n\nimport org.neo4j.ogm.config.Configuration;\nimport org.neo4j.ogm.config.ConfigurationSource;\nimport org.neo4j.ogm.session.SessionFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.Properties;\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\n@Repository\npublic class Neo4jDao {\n    private static final Logger logger = LoggerFactory.getLogger(Neo4jDao.class);\n    private static final String packages = \"cn.abel.neo4j.bean\";\n\n    private SessionFactory sessionFactory = null;\n\n    @Value(\"${neo4j.url}\")\n    private String boltUri;\n    @Value(\"${neo4j.username}\")\n    private String username;\n    @Value(\"${neo4j.password}\")\n    private String password;\n\n    /**\n     * 打开一个到neo4j的连接会话。\n     */\n    public Neo4jSession open() {\n        SessionFactory factory = getSessionFactory();\n        Neo4jSession session = new Neo4jSession(factory);\n        return session;\n    }\n\n    private synchronized SessionFactory getSessionFactory() {\n        if (sessionFactory == null) {\n            ConfigurationSource props = () -> {\n                Properties properties = new Properties();\n                properties.setProperty(\"URI\", boltUri);\n                properties.setProperty(\"username\", username);\n                properties.setProperty(\"password\", password);\n                return properties;\n            };\n            Configuration configuration = new Configuration.Builder(props).build();\n            sessionFactory = new SessionFactory(configuration, packages);\n        }\n        return sessionFactory;\n    }\n}\n\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/dao/Neo4jSession.java",
    "content": "package cn.abel.neo4j.dao;\n\nimport org.neo4j.ogm.session.Session;\nimport org.neo4j.ogm.session.SessionFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Map;\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\npublic class Neo4jSession {\n    private static final Logger logger = LoggerFactory.getLogger(Neo4jSession.class);\n    private Session session;\n    private static final int DEPTH_ENTITY = 1;\n\n    public Neo4jSession(SessionFactory factory) {\n        session = factory.openSession();\n    }\n\n    /**\n     * 执行cypher命令。\n     * 增、删、改、查的 cypher 命令都可以用此方法操作\n     *\n     * @param cypher\n     * @return\n     */\n    public Iterator<Map<String, Object>> exec(String cypher) {\n        long time = System.currentTimeMillis();\n        Iterator<Map<String, Object>> it = session.query(cypher, Collections.EMPTY_MAP).iterator();\n        logger.info(\"ExecCypher {} cost:{}ms\", cypher, System.currentTimeMillis() - time);\n        return it;\n    }\n\n\n    /**\n     * 存储对象\n     *\n     * @param o\n     * @return\n     */\n    public void execSave(Object o) {\n        long time = System.currentTimeMillis();\n        session.clear();\n        session.save(o);\n        logger.info(\"ExecCypher {} cost:{}ms\", o.toString(), System.currentTimeMillis() - time);\n    }\n\n    /**\n     * 清空 session 缓存。\n     */\n    public void clear() {\n        session.clear();\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/dto/GraphDTO.java",
    "content": "package cn.abel.neo4j.dto;\n\nimport java.util.List;\n\n/**\n * 用于输出图\n * @author yyb\n * @time 2020/3/24\n */\npublic class GraphDTO {\n    private List<Object> nodes;\n    private List<Object> links;\n\n    public List<Object> getNodes() {\n        return nodes;\n    }\n\n    public void setNodes(List<Object> nodes) {\n        this.nodes = nodes;\n    }\n\n    public List<Object> getLinks() {\n        return links;\n    }\n\n    public void setLinks(List<Object> links) {\n        this.links = links;\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/java/cn/abel/neo4j/service/KingService.java",
    "content": "package cn.abel.neo4j.service;\n\nimport cn.abel.neo4j.bean.King;\nimport cn.abel.neo4j.bean.Queen;\nimport cn.abel.neo4j.bean.relation.FatherAndSonRelation;\nimport cn.abel.neo4j.dao.KingDao;\nimport cn.abel.neo4j.dao.Neo4jDao;\nimport cn.abel.neo4j.dao.Neo4jSession;\nimport cn.abel.neo4j.dto.GraphDTO;\nimport org.neo4j.driver.internal.InternalNode;\nimport org.neo4j.driver.internal.InternalPath;\nimport org.neo4j.driver.internal.InternalRelationship;\nimport org.neo4j.driver.v1.types.Node;\nimport org.neo4j.driver.v1.types.Relationship;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.*;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\n@Service\npublic class KingService {\n    @Autowired\n    private Neo4jDao neo4jDao;\n\n    @Autowired\n    private KingDao kingDao;\n\n    /**\n     * 保存皇帝信息\n     *\n     * @param list\n     */\n    public void saveKing(List<King> list) {\n        Neo4jSession session = neo4jDao.open();\n        list.forEach(x -> {\n            session.execSave(x);\n        });\n    }\n\n    /**\n     * 保存皇后信息\n     *\n     * @param list\n     */\n    public void saveQueen(List<Queen> list) {\n        Neo4jSession session = neo4jDao.open();\n        list.forEach(x -> {\n            session.execSave(x);\n        });\n    }\n\n\n    /**\n     * 通过皇帝名字，查到当前的皇后和上一任皇帝\n     *\n     * @param\n     */\n    public GraphDTO getKingAndQueen(String kingName) {\n        Neo4jSession session = neo4jDao.open();\n        String cypher = \"match p=(a:King)-[r:`传位`]->(b:King)-[r2:`皇后`*1..]->(c:Queen) where a.name ='\" + kingName + \"' return p\";\n//        通过皇帝名字查询到当前皇帝皇后以及上一任皇帝皇后\n//        match p=(a:King)-[r:`传位`]->(b:King)-[r2:`皇后`*1..]->(c:Queen), (a:King)-[r3:`皇后`*1..]->(d:Queen) where b.name ='朱棣' return a,b,c,d\n        Iterator<Map<String, Object>> iterator = session.exec(cypher);\n        GraphDTO gto = mapToGraph(iterator);\n        return gto;\n    }\n\n\n    private GraphDTO mapToGraph(\n            Iterator<Map<String, Object>> neo4jDataIterator) {\n        Map<Long, Object> nodeMap = new HashMap<>();\n        Map<Long, Object> linkMap = new HashMap<>();\n\n        while (neo4jDataIterator.hasNext()) {\n            Map<String, Object> each = neo4jDataIterator.next();\n            if (!each.containsKey(\"p\")) {\n                continue;\n            }\n\n            InternalPath internalPath = (InternalPath) each.get(\"p\");\n            //归纳出所有节点。\n            for (Node node : internalPath.nodes()) {\n                InternalNode internalNode = (InternalNode) node;\n                if (nodeMap.containsKey(internalNode.id())) {\n                    continue;\n                }\n                nodeMap.put(internalNode.id(), internalNode);\n            }\n            //归纳出所有关系。\n            for (Relationship relation : internalPath.relationships()) {\n                InternalRelationship internalRelation = (InternalRelationship) relation;\n                if (linkMap.containsKey(internalRelation.id())) {\n                    continue;\n                }\n                linkMap.put(internalRelation.id(), internalRelation);\n            }\n        }\n\n        GraphDTO dto = new GraphDTO();\n        dto.setNodes(nodeMap.values().stream().collect(Collectors.toList()));\n        dto.setLinks(linkMap.values().stream().collect(Collectors.toList()));\n        return dto;\n    }\n\n\n    /**\n     * 查询一个皇帝信息，此处使用spring-data-neo4j 接口\n     *\n     * @param name\n     */\n    public King findByName(String name) {\n        King t = kingDao.findByName(name);\n        return t;\n    }\n\n\n    /**\n     * 获取当前节点下的所有king\n     *\n     * @param name\n     * @return\n     */\n    public List<King> getKings(String name) {\n        return kingDao.getKings(name);\n    }\n\n\n    /**\n     * 保存父子关系\n     *\n     * @param fatherName\n     * @param sonName\n     * @return\n     */\n    public void saveRelation(String fatherName, String sonName) {\n        King from = kingDao.findByName(fatherName);\n        King to = kingDao.findByName(sonName);\n        FatherAndSonRelation fatherAndSonRelation = new FatherAndSonRelation();\n        fatherAndSonRelation.setFrom(from);\n        fatherAndSonRelation.setTo(to);\n        from.addRelation(fatherAndSonRelation);\n        kingDao.save(from);\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/main/resources/application.properties",
    "content": "#application\nspring.application.name=springboot-neo4j\napplication.main=cn.abel.Application\nserver.port=9657\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\nserver.tomcat.max-threads=200\nserver.session-timeout=60\nlog4j.logger.java.sql.Connection=DEBUG\n\n\nlogging.file=./logs/springboot-neo4j/springboot-neo4j.log\n\nspring.data.neo4j.url=bolt://localhost:7687\nspring.data.neo4j.username=neo4j\nspring.data.neo4j.password=admin\n\n\nneo4j.url=bolt://localhost:7687\nneo4j.username=neo4j\nneo4j.password=admin"
  },
  {
    "path": "springboot-neo4j/src/main/resources/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-neo4j/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-neo4j</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"DEBUG\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-neo4j/src/test/java/cn/abel/neo4j/BaseTest.java",
    "content": "package cn.abel.neo4j;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * @author yyb\n * @time 2019/3/27\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@TestPropertySource(\"/application.properties\")\npublic class BaseTest {\n\n    @Configuration\n    @ComponentScan(basePackages = {\"cn.abel\"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class))\n    static class ComponentScanConfig {\n\n    }\n\n\n    @Test\n    public void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "springboot-neo4j/src/test/java/cn/abel/neo4j/service/InitData.java",
    "content": "package cn.abel.neo4j.service;\n\nimport cn.abel.neo4j.bean.King;\nimport cn.abel.neo4j.bean.Queen;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2020/3/24\n */\npublic class InitData {\n\n    public static List<King> initKing() {\n        List<King> kingList = new ArrayList<>();\n\n        King king1 = new King();\n        king1.setId(1L);\n        king1.setName(\"朱元璋\");\n        king1.setClan(\"朱五四之子朱棣之父\");\n        king1.setPosthumousTitle(\"高皇帝\");\n        king1.setTimes(\"洪武（1368年——1398年）\");\n        king1.setTempleNumber(\"太祖\");\n        king1.setTomb(\"孝陵\");\n        king1.setRemark(\"空印案，胡惟庸案\");\n\n        King king2 = new King();\n        king2.setId(2L);\n        king2.setName(\"朱允炆\");\n        king2.setClan(\"朱元璋之孙朱标次子\");\n        king2.setPosthumousTitle(\"成皇帝\");\n        king2.setTimes(\"建文（1399年——1402年）\");\n        king2.setTempleNumber(\"惠宗\");\n        king2.setTomb(\"上金贝古墓\");\n        king2.setRemark(\"\");\n\n\n        King king3 = new King();\n        king3.setId(3L);\n        king3.setName(\"朱棣\");\n        king3.setClan(\"朱元璋四子\");\n        king3.setPosthumousTitle(\"文皇帝\");\n        king3.setTimes(\"永乐（1403年——1424年）\");\n        king3.setTempleNumber(\"成祖（原为太宗）\");\n        king3.setTomb(\"长陵\");\n        king3.setRemark(\"\");\n\n        King king4 = new King();\n        king4.setId(4L);\n        king4.setName(\"朱高炽\");\n        king4.setClan(\"朱棣长子\");\n        king4.setPosthumousTitle(\"昭皇帝\");\n        king4.setTimes(\"洪熙（1424年——1425年）\");\n        king4.setTempleNumber(\"仁宗\");\n        king4.setTomb(\"献陵\");\n        king4.setRemark(\"\");\n\n        King king5 = new King();\n        king5.setId(5L);\n        king5.setName(\"朱瞻基\");\n        king5.setClan(\"朱高炽长子\");\n        king5.setPosthumousTitle(\"章皇帝\");\n        king5.setTimes(\"宣德（1426年——1435年）\");\n        king5.setTempleNumber(\"宣宗\");\n        king5.setTomb(\"景陵\");\n        king5.setRemark(\"\");\n\n        King king6 = new King();\n        king6.setId(6L);\n        king6.setName(\"朱祁镇\");\n        king6.setClan(\"朱瞻基长子\");\n        king6.setPosthumousTitle(\"睿皇帝\");\n        king6.setTimes(\"正统（1436年——1449年） 天顺（1457年——1464年）\");\n        king6.setTempleNumber(\"英宗\");\n        king6.setTomb(\"裕陵\");\n        king6.setRemark(\"\");\n\n        King king7 = new King();\n        king7.setId(7L);\n        king7.setName(\"朱祁钰\");\n        king7.setClan(\"朱瞻基次子（庶出），朱祁镇之弟（后英宗复位，代宗被废）\");\n        king7.setPosthumousTitle(\"景皇帝\");\n        king7.setTimes(\"景泰（1450年——1457年） \");\n        king7.setTempleNumber(\"代宗\");\n        king7.setTomb(\"景泰陵\");\n        king7.setRemark(\"\");\n\n        King king8 = new King();\n        king8.setId(8L);\n        king8.setName(\"朱见深\");\n        king8.setClan(\"乃朱祁镇长子（庶出），朱祁钰从子\");\n        king8.setPosthumousTitle(\"纯皇帝\");\n        king8.setTimes(\"成化（1465年——1487年）\");\n        king8.setTempleNumber(\"宪宗\");\n        king8.setTomb(\"茂陵\");\n        king8.setRemark(\"\");\n\n        King king9 = new King();\n        king9.setId(9L);\n        king9.setName(\"朱祐樘\");\n        king9.setClan(\"乃朱见深三子（庶出）\");\n        king9.setPosthumousTitle(\"敬皇帝\");\n        king9.setTimes(\"弘治（1488年——1505年）\");\n        king9.setTempleNumber(\"孝宗\");\n        king9.setTomb(\"泰陵\");\n        king9.setRemark(\"\");\n\n        King king10 = new King();\n        king10.setId(10L);\n        king10.setName(\"朱厚照\");\n        king10.setClan(\"乃朱祐樘长子（武宗无嗣，乃由旁支皇室选择朱厚熜入继大统）\");\n        king10.setPosthumousTitle(\"高皇帝\");\n        king10.setTimes(\"洪武（1368年——1398年）\");\n        king10.setTempleNumber(\"武宗\");\n        king10.setTomb(\"孝陵\");\n        king10.setRemark(\"\");\n\n        King king11 = new King();\n        king11.setId(11L);\n        king11.setName(\"朱厚熜\");\n        king11.setClan(\"乃朱见深四子兴献王朱祐杬（庶出）之嫡长子，朱祐樘从子，朱厚照从弟\");\n        king11.setPosthumousTitle(\"肃皇帝\");\n        king11.setTimes(\"嘉靖（1522年——1566年）\");\n        king11.setTempleNumber(\"世宗\");\n        king11.setTomb(\"永陵\");\n        king11.setRemark(\"大仪礼\");\n\n        King king12 = new King();\n        king12.setId(12L);\n        king12.setName(\"朱载垕\");\n        king12.setClan(\"乃朱厚熜三子（庶出）\");\n        king12.setPosthumousTitle(\"庄皇帝\");\n        king12.setTimes(\"隆庆（1567年——1572年）\");\n        king12.setTempleNumber(\"穆宗\");\n        king12.setTomb(\"昭陵\");\n        king12.setRemark(\"\");\n\n\n        King king13 = new King();\n        king13.setId(13L);\n        king13.setName(\"朱翊钧\");\n        king13.setClan(\"乃朱载垕三子（庶出）\");\n        king13.setPosthumousTitle(\"显皇帝\");\n        king13.setTimes(\"万历（1573年——1620年）\");\n        king13.setTempleNumber(\"神宗\");\n        king13.setTomb(\"定陵\");\n        king13.setRemark(\"\");\n\n        King king14 = new King();\n        king14.setId(14L);\n        king14.setName(\"朱常洛\");\n        king14.setClan(\"乃朱翊钧长子\");\n        king14.setPosthumousTitle(\"贞皇帝\");\n        king14.setTimes(\"泰昌（1620年）实际在位一个月\");\n        king14.setTempleNumber(\"光宗\");\n        king14.setTomb(\"庆陵\");\n        king14.setRemark(\"\");\n\n\n        King king15 = new King();\n        king15.setId(15L);\n        king15.setName(\"朱由校\");\n        king15.setClan(\"乃朱常洛长子（庶出）（熹宗死后无嗣，乃诏令五弟信王朱由检入继大统）\");\n        king15.setPosthumousTitle(\"悊皇帝\");\n        king15.setTimes(\"天启（1621年——1627年）\");\n        king15.setTempleNumber(\"熹宗\");\n        king15.setTomb(\"德陵\");\n        king15.setRemark(\"\");\n\n\n        King king16 = new King();\n        king16.setId(16L);\n        king16.setName(\"朱由检\");\n        king16.setClan(\"乃朱常洛五子（庶出）（毅宗死后，明朝覆灭，宗室乃于南方割据）\");\n        king16.setPosthumousTitle(\"烈皇帝\");\n        king16.setTimes(\"崇祯（1628年——1644年）\");\n        king16.setTempleNumber(\"毅宗（原为思宗）\");\n        king16.setTomb(\"思陵\");\n        king16.setRemark(\"\");\n\n\n        king1.setSuccessor(king2);\n        king2.setSuccessor(king3);\n        king3.setSuccessor(king4);\n        king4.setSuccessor(king5);\n        king5.setSuccessor(king6);\n        king6.setSuccessor(king7);\n        king7.setSuccessor(king8);\n        king8.setSuccessor(king9);\n        king9.setSuccessor(king10);\n        king10.setSuccessor(king11);\n        king11.setSuccessor(king12);\n        king12.setSuccessor(king13);\n        king13.setSuccessor(king14);\n        king14.setSuccessor(king15);\n        king15.setSuccessor(king16);\n\n        kingList.add(king1);\n        kingList.add(king2);\n        kingList.add(king3);\n        kingList.add(king4);\n        kingList.add(king5);\n        kingList.add(king6);\n        kingList.add(king7);\n        kingList.add(king8);\n        kingList.add(king9);\n        kingList.add(king10);\n        kingList.add(king11);\n        kingList.add(king12);\n        kingList.add(king13);\n        kingList.add(king14);\n        kingList.add(king15);\n        kingList.add(king16);\n\n\n        return kingList;\n    }\n\n    public static List<Queen> initQueen() {\n\n        King king1 = new King();\n        king1.setId(1L);\n        king1.setName(\"朱元璋\");\n        king1.setClan(\"朱五四之子朱棣之父\");\n        king1.setPosthumousTitle(\"高皇帝\");\n        king1.setTimes(\"洪武（1368年——1398年）\");\n        king1.setTempleNumber(\"太祖\");\n        king1.setTomb(\"孝陵\");\n        king1.setRemark(\"空印案，胡惟庸案\");\n\n        King king2 = new King();\n        king2.setId(2L);\n        king2.setName(\"朱允炆\");\n        king2.setClan(\"朱元璋之孙朱标次子\");\n        king2.setPosthumousTitle(\"成皇帝\");\n        king2.setTimes(\"建文（1399年——1402年）\");\n        king2.setTempleNumber(\"惠宗\");\n        king2.setTomb(\"上金贝古墓\");\n        king2.setRemark(\"\");\n\n\n        King king3 = new King();\n        king3.setId(3L);\n        king3.setName(\"朱棣\");\n        king3.setClan(\"朱元璋四子\");\n        king3.setPosthumousTitle(\"文皇帝\");\n        king3.setTimes(\"永乐（1403年——1424年）\");\n        king3.setTempleNumber(\"成祖（原为太宗）\");\n        king3.setTomb(\"长陵\");\n        king3.setRemark(\"\");\n\n        King king4 = new King();\n        king4.setId(4L);\n        king4.setName(\"朱高炽\");\n        king4.setClan(\"朱棣长子\");\n        king4.setPosthumousTitle(\"昭皇帝\");\n        king4.setTimes(\"洪熙（1424年——1425年）\");\n        king4.setTempleNumber(\"仁宗\");\n        king4.setTomb(\"献陵\");\n        king4.setRemark(\"\");\n\n        King king5 = new King();\n        king5.setId(5L);\n        king5.setName(\"朱瞻基\");\n        king5.setClan(\"朱高炽长子\");\n        king5.setPosthumousTitle(\"章皇帝\");\n        king5.setTimes(\"宣德（1426年——1435年）\");\n        king5.setTempleNumber(\"宣宗\");\n        king5.setTomb(\"景陵\");\n        king5.setRemark(\"\");\n\n        King king6 = new King();\n        king6.setId(6L);\n        king6.setName(\"朱祁镇\");\n        king6.setClan(\"朱瞻基长子\");\n        king6.setPosthumousTitle(\"睿皇帝\");\n        king6.setTimes(\"正统（1436年——1449年） 天顺（1457年——1464年）\");\n        king6.setTempleNumber(\"英宗\");\n        king6.setTomb(\"裕陵\");\n        king6.setRemark(\"\");\n\n        King king7 = new King();\n        king7.setId(7L);\n        king7.setName(\"朱祁钰\");\n        king7.setClan(\"朱瞻基次子（庶出），朱祁镇之弟（后英宗复位，代宗被废）\");\n        king7.setPosthumousTitle(\"景皇帝\");\n        king7.setTimes(\"景泰（1450年——1457年） \");\n        king7.setTempleNumber(\"代宗\");\n        king7.setTomb(\"景泰陵\");\n        king7.setRemark(\"\");\n\n        King king8 = new King();\n        king8.setId(8L);\n        king8.setName(\"朱见深\");\n        king8.setClan(\"乃朱祁镇长子（庶出），朱祁钰从子\");\n        king8.setPosthumousTitle(\"纯皇帝\");\n        king8.setTimes(\"成化（1465年——1487年）\");\n        king8.setTempleNumber(\"宪宗\");\n        king8.setTomb(\"茂陵\");\n        king8.setRemark(\"\");\n\n        King king9 = new King();\n        king9.setId(9L);\n        king9.setName(\"朱祐樘\");\n        king9.setClan(\"乃朱见深三子（庶出）\");\n        king9.setPosthumousTitle(\"敬皇帝\");\n        king9.setTimes(\"弘治（1488年——1505年）\");\n        king9.setTempleNumber(\"孝宗\");\n        king9.setTomb(\"泰陵\");\n        king9.setRemark(\"\");\n\n        King king10 = new King();\n        king10.setId(10L);\n        king10.setName(\"朱厚照\");\n        king10.setClan(\"乃朱祐樘长子（武宗无嗣，乃由旁支皇室选择朱厚熜入继大统）\");\n        king10.setPosthumousTitle(\"高皇帝\");\n        king10.setTimes(\"洪武（1368年——1398年）\");\n        king10.setTempleNumber(\"武宗\");\n        king10.setTomb(\"孝陵\");\n        king10.setRemark(\"\");\n\n        King king11 = new King();\n        king11.setId(11L);\n        king11.setName(\"朱厚熜\");\n        king11.setClan(\"乃朱见深四子兴献王朱祐杬（庶出）之嫡长子，朱祐樘从子，朱厚照从弟\");\n        king11.setPosthumousTitle(\"肃皇帝\");\n        king11.setTimes(\"嘉靖（1522年——1566年）\");\n        king11.setTempleNumber(\"世宗\");\n        king11.setTomb(\"永陵\");\n        king11.setRemark(\"大仪礼\");\n\n        King king12 = new King();\n        king12.setId(12L);\n        king12.setName(\"朱载垕\");\n        king12.setClan(\"乃朱厚熜三子（庶出）\");\n        king12.setPosthumousTitle(\"庄皇帝\");\n        king12.setTimes(\"隆庆（1567年——1572年）\");\n        king12.setTempleNumber(\"穆宗\");\n        king12.setTomb(\"昭陵\");\n        king12.setRemark(\"\");\n\n\n        King king13 = new King();\n        king13.setId(13L);\n        king13.setName(\"朱翊钧\");\n        king13.setClan(\"乃朱载垕三子（庶出）\");\n        king13.setPosthumousTitle(\"显皇帝\");\n        king13.setTimes(\"万历（1573年——1620年）\");\n        king13.setTempleNumber(\"神宗\");\n        king13.setTomb(\"定陵\");\n        king13.setRemark(\"\");\n\n        King king14 = new King();\n        king14.setId(14L);\n        king14.setName(\"朱常洛\");\n        king14.setClan(\"乃朱翊钧长子\");\n        king14.setPosthumousTitle(\"贞皇帝\");\n        king14.setTimes(\"泰昌（1620年）实际在位一个月\");\n        king14.setTempleNumber(\"光宗\");\n        king14.setTomb(\"庆陵\");\n        king14.setRemark(\"\");\n\n\n        King king15 = new King();\n        king15.setId(15L);\n        king15.setName(\"朱由校\");\n        king15.setClan(\"乃朱常洛长子（庶出）（熹宗死后无嗣，乃诏令五弟信王朱由检入继大统）\");\n        king15.setPosthumousTitle(\"悊皇帝\");\n        king15.setTimes(\"天启（1621年——1627年）\");\n        king15.setTempleNumber(\"熹宗\");\n        king15.setTomb(\"德陵\");\n        king15.setRemark(\"\");\n\n\n        King king16 = new King();\n        king16.setId(16L);\n        king16.setName(\"朱由检\");\n        king16.setClan(\"乃朱常洛五子（庶出）（毅宗死后，明朝覆灭，宗室乃于南方割据）\");\n        king16.setPosthumousTitle(\"烈皇帝\");\n        king16.setTimes(\"崇祯（1628年——1644年）\");\n        king16.setTempleNumber(\"毅宗（原为思宗）\");\n        king16.setTomb(\"思陵\");\n        king16.setRemark(\"\");\n\n        /**\n         * 初始化皇后信息\n         */\n        List<Queen> queenList = new ArrayList<>();\n\n        Queen queen1 = new Queen();\n        queen1.setId(101L);\n        queen1.setPosthumousTitle(\"孝慈高皇后\");\n        queen1.setName(\"马秀英\");\n        queen1.setRemark(\"安徽宿州人，早年丧母，被郭子兴夫妇收养为义女。1382年（洪武十五年）五十一岁的马皇后病逝。\");\n        queen1.setTimes(\"1368年1月－1382年\");\n        queen1.setSon(\"明兴宗朱标、秦愍王朱樉、晋恭王朱㭎、明成祖朱棣、周定王朱橚（五子皆存疑），宁国公主，安庆公主\");\n        queen1.setKing(king1);\n\n\n        Queen queen2 = new Queen();\n        queen2.setId(102L);\n        queen2.setPosthumousTitle(\"孝愍让皇后\");\n        queen2.setName(\"马全女\");\n        queen2.setRemark(\"洪武二十八年十月,册后为皇太孙妃。建文改元,立为后。生二子,文煃、文圭。\");\n        queen2.setTimes(\"1399年－1402年\");\n        queen2.setSon(\"和简太子朱文奎，润怀王朱文圭\");\n        queen2.setKing(king2);\n\n        Queen queen3 = new Queen();\n        queen3.setId(103L);\n        queen3.setPosthumousTitle(\"孝文皇后\");\n        queen3.setName(\"徐氏 \");\n        queen3.setTimes(\"1402年11月－1407年\");\n        queen3.setSon(\"明仁宗朱高炽、汉王朱高煦、赵王朱高燧\");\n        queen3.setRemark(\"洪武九年(1376年)册封为燕王妃，朱棣称帝册封为皇后。永乐五年(1407年)七月四日去世,享年46岁。\");\n        queen3.setKing(king3);\n\n        Queen queen4 = new Queen();\n        queen4.setId(104L);\n        queen4.setPosthumousTitle(\"诚孝昭皇后\");\n        queen4.setName(\"张氏\");\n        queen4.setRemark(\"仁宗元配,永城人,指挥使赠彭城侯张麒诚孝昭皇后画像之女。洪武二十八年(1395年)封燕王世子妃,永乐二年(1404年)封皇太子妃。仁宗即位,册立为皇后。宣宗即位,尊为皇太后。英宗即位，尊为太皇太后。正统七年(1442年)十月十八日去世.\");\n        queen4.setTimes(\"1424年7月－1442年\");\n        queen4.setSon(\"明宣宗朱瞻基、越靖王朱瞻墉、襄宪王朱瞻墡、嘉兴公主\");\n        queen4.setKing(king4);\n\n        Queen queen5 = new Queen();\n        queen5.setId(105L);\n        queen5.setPosthumousTitle(\"恭让章皇后\");\n        queen5.setName(\"胡善祥\");\n        queen5.setTimes(\"1426年－1428年\");\n        queen5.setSon(\"顺德公主\");\n        queen5.setRemark(\"皇后，后被废黜，后被追谥为恭让章皇后\");\n        queen5.setKing(king5);\n\n        Queen queen51 = new Queen();\n        queen51.setId(106L);\n        queen51.setPosthumousTitle(\"孝翼皇后\");\n        queen51.setName(\"吴氏\");\n        queen51.setSon(\"明代宗朱祁钰\");\n        queen51.setRemark(\"太子妾，贤妃，后成皇太后，后被废，南明追谥孝翼温惠淑慎慈仁匡天锡圣太后\");\n        queen51.setKing(king5);\n\n        Queen queen52 = new Queen();\n        queen52.setId(107L);\n        queen52.setPosthumousTitle(\"孝恭章皇后\");\n        queen52.setName(\"孙氏\");\n        queen52.setTimes(\"1426年－1462年\");\n        queen52.setSon(\"常德公主、明英宗（存疑）\");\n        queen52.setRemark(\"\");\n        queen52.setKing(king5);\n\n        Queen queen6 = new Queen();\n        queen6.setId(108L);\n        queen6.setPosthumousTitle(\"孝庄睿皇后\");\n        queen6.setName(\"钱氏\");\n        queen6.setTimes(\"1442年－1468年6月\");\n        queen6.setRemark(\"英宗元配,海州人,都指挥佥事（后封安昌伯）钱贵女。正统七年(1442年)立为皇后。宪宗即位,尊为皇太后,加“慈懿”徽号。成化四年（1468年）六月二十六日,钱氏病故。  \");\n        queen6.setKing(king6);\n\n        Queen queen61 = new Queen();\n        queen61.setId(109L);\n        queen61.setPosthumousTitle(\"孝肃后\");\n        queen61.setName(\"周氏\");\n        queen61.setTimes(\"1464年－1504\");\n        queen61.setSon(\"重庆公主、明宪宗朱见深、崇简王朱见泽\");\n        queen61.setRemark(\"宪宗生母,昌平州文宁里柳林村(今属北京市海淀区)人,锦衣卫千户追封庆云侯赠宁国公周能的女儿。正统十二年(1447年)生宪宗皇帝,天顺元年（1457年）册封为贵妃。宪宗即位,尊为皇太后。孝宗即位后,尊为太皇太后。弘治十七年（1504年）三月一日去世.\");\n        queen61.setKing(king6);\n\n        Queen queen7 = new Queen();\n        queen7.setId(110L);\n        queen7.setPosthumousTitle(\"孝渊皇后\");\n        queen7.setName(\"汪氏\");\n        queen7.setTimes(\"1449年－1452年\");\n        queen7.setSon(\"固安公主、二公主（出家）\");\n        queen7.setRemark(\"北京人，祖父汪泉世为金吾左卫指挥使。正统十年(1445)，郕王朱祁钰18岁，册封汪氏为郕王妃。正统十四年(1449) 册封王妃汪氏为皇后。进汪皇后祖父汪泉为都指挥同知；，汪氏去世与景帝合葬金山。\");\n        queen7.setKing(king7);\n\n        Queen queen71 = new Queen();\n        queen71.setId(111L);\n        queen71.setPosthumousTitle(\"肃孝皇后\");\n        queen71.setName(\"杭氏\");\n        queen71.setSon(\"怀献太子朱见济\");\n        queen71.setTimes(\"1452年－1453年\");\n        queen71.setRemark(\"妾，后为贵妃，后成皇后，后被明英宗追废\");\n        queen71.setKing(king7);\n\n        Queen queen8 = new Queen();\n        queen8.setId(112L);\n        queen8.setPosthumousTitle(\"皇后\");\n        queen8.setName(\"吴氏\");\n        queen8.setTimes(\"1464年7月27日－1464年8月28日\");\n        queen8.setSon(\"曾抚养明孝宗朱祐樘\");\n        queen8.setRemark(\"皇后，后被废黜,在位仅31日。为明朝在位时期最短的皇后。\");\n        queen8.setKing(king8);\n\n        Queen queen81 = new Queen();\n        queen81.setId(113L);\n        queen81.setPosthumousTitle(\"孝贞纯皇后\");\n        queen81.setName(\"王氏\");\n        queen81.setTimes(\"1464年10月12日－1518年2月\");\n        queen81.setRemark(\"皇后，后成皇太后\");\n        queen81.setKing(king8);\n\n\n        Queen queen82 = new Queen();\n        queen82.setId(114L);\n        queen82.setPosthumousTitle(\"孝穆皇后\");\n        queen82.setName(\"纪氏\");\n        queen82.setSon(\"明孝宗朱祐樘\");\n        queen82.setRemark(\"宫人，后成淑妃，后被追谥孝穆皇后, 瑶族人。暴死\");\n        queen82.setKing(king8);\n\n        Queen queen83 = new Queen();\n        queen83.setId(115L);\n        queen83.setPosthumousTitle(\"孝惠皇后\");\n        queen83.setName(\"邵氏\");\n        queen83.setSon(\"宸妃，后成贵妃，嘉靖帝尊为寿安皇太后，后被追谥孝惠皇后\");\n        queen83.setRemark(\"宫人，后成淑妃，后被追谥孝穆皇后, 瑶族人。暴死\");\n        queen83.setKing(king8);\n\n        Queen queen9 = new Queen();\n        queen9.setId(116L);\n        queen9.setPosthumousTitle(\"孝成敬皇后\");\n        queen9.setName(\"张氏\");\n        queen9.setTimes(\"1486年－1541年\");\n        queen9.setSon(\"明武宗朱厚照、朱厚炜、太康公主朱秀荣\");\n        queen9.setRemark(\"皇后，后成皇伯母皇太后，追谥孝康敬皇后，后改谥孝成敬皇后,丈夫孝宗在世期间未曾册封嫔妃，是中国历史上唯一终生一夫一妻的皇帝\");\n        queen9.setKing(king9);\n\n\n\n        Queen queen10 = new Queen();\n        queen10.setId(117L);\n        queen10.setPosthumousTitle(\"孝静皇后\");\n        queen10.setName(\"夏氏\");\n        queen10.setTimes(\"1506年－1535年1月\");\n        queen10.setRemark(\"皇后，嘉靖帝尊封为皇嫂庄肃皇后\");\n        queen10.setKing(king10);\n\n\n\n        Queen queen11 = new Queen();\n        queen11.setId(118L);\n        queen11.setPosthumousTitle(\"孝洁肃皇后\");\n        queen11.setName(\"陈氏\");\n        queen11.setTimes(\"1522年－1528年10月\");\n        queen11.setRemark(\"皇后，谥悼灵皇后，后改谥孝洁恭懿慈睿安庄相天翊圣肃皇后, 受惊流产而亡\");\n        queen11.setKing(king11);\n\n        Queen queen12 = new Queen();\n        queen12.setId(119L);\n        queen12.setPosthumousTitle(\"孝懿庄皇后\");\n        queen12.setName(\"李氏\");\n        queen12.setTimes(\"?－1558年4月\");\n        queen12.setSon(\"宪怀太子朱翊、蓬莱公主\");\n        queen12.setRemark(\"结髪之妻，正室，后被追谥为孝懿贞惠顺哲恭仁俪天襄圣庄皇后\");\n        queen12.setKing(king12);\n\n\n        Queen queen121 = new Queen();\n        queen121.setId(120L);\n        queen121.setPosthumousTitle(\"孝安皇后\");\n        queen121.setName(\"陈氏\");\n        queen121.setTimes(\"1567年3月－1596年7月\");\n        queen121.setSon(\"太和公主\");\n        queen121.setRemark(\"继室，后为皇后，后成皇太后，后被追谥为孝安贞懿恭纯温惠佐天弘圣皇后\");\n        queen121.setKing(king12);\n\n        Queen queen13 = new Queen();\n        queen13.setId(121L);\n        queen13.setPosthumousTitle(\"孝端皇后\");\n        queen13.setName(\"王喜姐\");\n        queen13.setTimes(\"1578年－1620年\");\n        queen13.setRemark(\"荣昌公主朱轩媖\");\n        queen13.setKing(king13);\n\n\n        Queen queen14 = new Queen();\n        queen14.setId(122L);\n        queen14.setPosthumousTitle(\"孝元贞皇后\");\n        queen14.setName(\"郭氏\");\n        queen14.setSon(\"怀淑公主朱徽娟\");\n        queen14.setRemark(\"结髪之妻，正室太子妃，后被追谥为孝元昭懿哲惠庄仁合天弼圣贞皇后\");\n        queen14.setKing(king14);\n\n\n        Queen queen15 = new Queen();\n        queen15.setId(123L);\n        queen15.setPosthumousTitle(\"孝哀悊皇后\");\n        queen15.setName(\"张氏\");\n        queen15.setTimes(\"1621年4月－1644年2月28日\");\n        queen15.setSon(\"太子朱慈燃\");\n        queen15.setRemark(\"皇后，崇祯帝尊封为皇嫂懿安皇后，南明追谥孝哀慈靖恭惠温贞偕天协圣悊皇后,明亡时自缢身亡。\");\n        queen15.setKing(king15);\n\n\n        Queen queen16 = new Queen();\n        queen16.setId(124L);\n        queen16.setPosthumousTitle(\"孝节烈皇后\");\n        queen16.setName(\"周氏\");\n        queen16.setTimes(\"1628年－1644年2月28日\");\n        queen16.setSon(\"坤仪公主、明悼帝朱慈烺、怀隐王朱慈烜、定哀王朱慈炯\");\n        queen16.setRemark(\"结髪之妻，正室，后成皇后，清追谥为庄烈愍皇后，南明追谥孝节贞肃渊恭庄毅奉天靖圣烈皇后,自杀\");\n        queen16.setKing(king16);\n\n\n        queenList.add(queen1);\n        queenList.add(queen2);\n        queenList.add(queen3);\n        queenList.add(queen4);\n        queenList.add(queen5);\n        queenList.add(queen5);\n        queenList.add(queen51);\n        queenList.add(queen52);\n\n        queenList.add(queen6);\n        queenList.add(queen61);\n\n        queenList.add(queen7);\n        queenList.add(queen71);\n\n        queenList.add(queen8);\n        queenList.add(queen81);\n        queenList.add(queen82);\n        queenList.add(queen83);\n\n        queenList.add(queen9);\n        queenList.add(queen10);\n        queenList.add(queen11);\n        queenList.add(queen12);\n        queenList.add(queen121);\n\n        queenList.add(queen13);\n        queenList.add(queen14);\n        queenList.add(queen15);\n        queenList.add(queen16);\n\n        return queenList;\n    }\n}\n"
  },
  {
    "path": "springboot-neo4j/src/test/java/cn/abel/neo4j/service/KingServiceTest.java",
    "content": "package cn.abel.neo4j.service;\n\nimport cn.abel.neo4j.BaseTest;\nimport cn.abel.neo4j.bean.King;\nimport cn.abel.neo4j.bean.Queen;\nimport cn.abel.neo4j.dao.KingDao;\nimport cn.abel.neo4j.dto.GraphDTO;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n\n/**\n * @author yyb\n * @time 2020/3/23\n */\npublic class KingServiceTest extends BaseTest {\n    @Autowired\n    private KingService kingService;\n    @Autowired\n    private KingDao kingDao;\n\n\n    @Test\n    public void saveKing() throws Exception {\n        List<King> kingList = InitData.initKing();\n        kingService.saveKing(kingList);\n    }\n\n    @Test\n    public void saveQueen() throws Exception {\n        List<Queen> queenList = InitData.initQueen();\n        kingService.saveQueen(queenList);\n    }\n\n    @Test\n    public void saveRelation() throws Exception {\n        kingService.saveRelation(\"朱元璋\", \"朱棣\");\n    }\n\n    @Test\n    public void getOneKing() throws Exception {\n        King king = kingService.findByName(\"朱棣\");\n        System.out.println();\n\n    }\n\n    @Test\n    public void getKingAndQueen() throws Exception {\n        GraphDTO graphDTO = kingService.getKingAndQueen(\"朱棣\");\n        System.out.println();\n\n    }\n\n}"
  },
  {
    "path": "springboot-redis-queue/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-redis-queue</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--redis-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>redis.clients</groupId>\n            <artifactId>jedis</artifactId>\n            <version>3.0.1</version>\n        </dependency>\n\n\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.18.1</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-redis-queue/src/main/java/cn/abel/queue/Application.java",
    "content": "package cn.abel.queue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-redis-queue/src/main/java/cn/abel/queue/config/RedisConfig.java",
    "content": "package cn.abel.queue.config;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.commons.pool2.impl.GenericObjectPoolConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.cache.annotation.CachingConfigurerSupport;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.interceptor.KeyGenerator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisPassword;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\nimport java.time.Duration;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@Configuration\n@EnableCaching\npublic class RedisConfig extends CachingConfigurerSupport {\n    /**\n     * logger\n     */\n    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);\n    @Value(\"${spring.redis.database}\")\n    private Integer database;\n    @Value(\"${spring.redis.host}\")\n    private String host;\n    @Value(\"${spring.redis.port}\")\n    private Integer port;\n    @Value(\"${spring.redis.password}\")\n    private String password;\n    @Value(\"${spring.redis.lettuce.pool.max-active}\")\n    private Integer maxActive;\n    @Value(\"${spring.redis.lettuce.pool.max-wait}\")\n    private Integer maxWait;\n    @Value(\"${spring.redis.lettuce.pool.max-idle}\")\n    private Integer maxIdle;\n    @Value(\"${spring.redis.lettuce.pool.min-idle}\")\n    private Integer minIdle;\n    @Value(\"${spring.redis.lettuce.shutdown-timeout}\")\n    private Integer timeout;\n\n    /**\n     * 在使用@Cacheable时，如果不指定key，则使用这个默认的key生成器生成的key\n     *\n     * @return\n     */\n    @Override\n    @Bean\n    public KeyGenerator keyGenerator() {\n        return (target, method, params) -> {\n            StringBuilder sb = new StringBuilder();\n            sb.append(target.getClass().getName());\n            sb.append(method.getName());\n            for (Object obj : params) {\n                sb.append(obj.toString());\n            }\n            return sb.toString();\n        };\n    }\n\n    @Bean(name = \"redisTemplate\")\n    public RedisTemplate<Object, Object> redisTemplate() {\n        return getTemplate(redisConnectionFactory());\n    }\n\n    private RedisConnectionFactory redisConnectionFactory() {\n        return connectionFactory(maxActive, maxIdle, minIdle, maxWait, host, password, timeout, port, database);\n    }\n\n\n    /**\n     * 创建连接\n     *\n     * @param maxActive\n     * @param maxIdle\n     * @param minIdle\n     * @param maxWait\n     * @param host\n     * @param password\n     * @param timeout\n     * @param port\n     * @param database\n     * @return\n     */\n    private RedisConnectionFactory connectionFactory(Integer maxActive,\n                                                     Integer maxIdle,\n                                                     Integer minIdle,\n                                                     Integer maxWait,\n                                                     String host,\n                                                     String password,\n                                                     Integer timeout,\n                                                     Integer port,\n                                                     Integer database) {\n        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();\n        redisStandaloneConfiguration.setHostName(host);\n        redisStandaloneConfiguration.setPort(port);\n        redisStandaloneConfiguration.setDatabase(database);\n        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));\n\n        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();\n        poolConfig.setMaxTotal(maxActive);\n        poolConfig.setMinIdle(minIdle);\n        poolConfig.setMaxIdle(maxIdle);\n        poolConfig.setMaxWaitMillis(maxWait);\n        LettuceClientConfiguration lettucePoolingConfig = LettucePoolingClientConfiguration.builder()\n                .poolConfig(poolConfig).shutdownTimeout(Duration.ofMillis(timeout)).build();\n        LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration,\n                lettucePoolingConfig);\n        connectionFactory.afterPropertiesSet();\n\n        return connectionFactory;\n    }\n\n    /**\n     * 创建 RedisTemplate 连接类型，此处为hash\n     *\n     * @param factory\n     * @return\n     */\n    private RedisTemplate<Object, Object> getTemplate(RedisConnectionFactory factory) {\n        RedisTemplate<Object, Object> template = new RedisTemplate<>();\n        template.setConnectionFactory(factory);\n        template.setValueSerializer(jackson2JsonRedisSerializer(new ObjectMapper()));\n        template.setKeySerializer(new StringRedisSerializer());\n        template.setHashKeySerializer(new StringRedisSerializer());\n        template.setHashValueSerializer(jackson2JsonRedisSerializer(new ObjectMapper()));\n\n        template.afterPropertiesSet();\n        return template;\n    }\n\n    /**\n     * 对value 进行序列化\n     *\n     * @param objectMapper\n     * @return\n     */\n    private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer(ObjectMapper objectMapper) {\n        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =\n                new Jackson2JsonRedisSerializer<>(Object.class);\n        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);\n        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        return jackson2JsonRedisSerializer;\n    }\n}\n"
  },
  {
    "path": "springboot-redis-queue/src/main/java/cn/abel/queue/controller/PublisherController.java",
    "content": "package cn.abel.queue.controller;\n\nimport cn.abel.queue.service.ProducerService;\nimport cn.abel.queue.service.ReceiverService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n\n@RestController\n@RequestMapping(\"/publisher\")\npublic class PublisherController {\n    @Autowired\n    private ProducerService producerService;\n    @Autowired\n    private ReceiverService receiverService;\n\n    @RequestMapping(value = \"{name}\",method = RequestMethod.GET)\n    public String sendMessage(@PathVariable(\"name\") String name) {\n        return producerService.sendMessage(name);\n    }\n\n\n    @RequestMapping(value = \"/get\",method =RequestMethod.GET )\n    public String getMessage() {\n        return receiverService.getMessage();\n    }\n\n}\n"
  },
  {
    "path": "springboot-redis-queue/src/main/java/cn/abel/queue/service/ProducerService.java",
    "content": "package cn.abel.queue.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\n\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n\n@Service\npublic class ProducerService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public String sendMessage(String name) {\n        try {\n            redisTemplate.opsForList().leftPush(\"quere\", name);\n            return \"消息发送成功了\";\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            return \"消息发送失败了\";\n        }\n    }\n\n}"
  },
  {
    "path": "springboot-redis-queue/src/main/java/cn/abel/queue/service/ReceiverService.java",
    "content": "package cn.abel.queue.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@Service\npublic class ReceiverService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public String getMessage() {\n        String value = redisTemplate.opsForList().rightPop(\"quere\");\n        return value;\n    }\n}\n\n"
  },
  {
    "path": "springboot-redis-queue/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=9666\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200\nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=redis-queue\napplication.main=cn.abel.queue.Application\n\n## LOG\nlogging.file=./logs/redis-queue.log\n\n\n## spring cache\n#\\u7F13\\u5B58\\u7684\\u540D\\u79F0\\u96C6\\u5408\\uFF0C\\u591A\\u4E2A\\u91C7\\u7528\\u9017\\u53F7\\u5206\\u5272\n#spring.cache.cache-names=admin,role\n#\\u7F13\\u5B58\\u7684\\u7C7B\\u578B\\uFF0C\\u5B98\\u65B9\\u63D0\\u4F9B\\u4E86\\u5F88\\u591A\\uFF0C\\u8FD9\\u91CC\\u6211\\u4EEC\\u586B\\u5199redis\nspring.cache.type=redis\n#\\u662F\\u5426\\u7F13\\u5B58null\\u6570\\u636E\\uFF0C\\u9ED8\\u8BA4\\u662Ffalse\n#spring.cache.redis.cache-null-values=false\n#redis\\u4E2D\\u7F13\\u5B58\\u8D85\\u65F6\\u7684\\u65F6\\u95F4\\uFF0C\\u9ED8\\u8BA460000ms\n#spring.cache.redis.time-to-live=60000\n#\\u7F13\\u5B58\\u6570\\u636Ekey\\u662F\\u5426\\u4F7F\\u7528\\u524D\\u7F00\\uFF0C\\u9ED8\\u8BA4\\u662Ftrue\n#spring.cache.redis.use-key-prefix=true\n#\\u7F13\\u5B58\\u6570\\u636Ekey\\u7684\\u524D\\u7F00\\uFF0C\\u5728\\u4E0A\\u9762\\u7684\\u914D\\u7F6E\\u4E3Atrue\\u65F6\\u6709\\u6548\\uFF0C\n\n# Redis\\u6570\\u636E\\u5E93\\u7D22\\u5F15\\uFF08\\u9ED8\\u8BA4\\u5E93\\uFF09\nspring.redis.database=2\n# Redis\\u670D\\u52A1\\u5668\\u5730\\u5740\nspring.redis.host=127.0.0.1\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u7AEF\\u53E3\nspring.redis.port=6379\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u5BC6\\u7801\\uFF08\\u9ED8\\u8BA4\\u4E3A\\u7A7A\\uFF09\nspring.redis.password=\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-active=100\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u963B\\u585E\\u7B49\\u5F85\\u65F6\\u95F4\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-wait=1000\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5927\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.max-idle=50\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.min-idle=0\n# \\u8FDE\\u63A5\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.redis.lettuce.shutdown-timeout=0"
  },
  {
    "path": "springboot-redis-queue/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-redis-queue/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>demo</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-rocketmq/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-rocketmq</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-client</artifactId>\n            <version>4.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.codehaus.groovy</groupId>\n            <artifactId>groovy</artifactId>\n        </dependency>\n\n\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.18.1</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-rocketmq/src/main/java/cn/abel/queue/Application.java",
    "content": "package cn.abel.queue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-rocketmq/src/main/java/cn/abel/queue/config/JmsConfig.java",
    "content": "package cn.abel.queue.config;\n\n/**\n * @author yyb\n * @time 2019/11/26\n */\npublic class JmsConfig {\n    /**\n     * Name Server 地址，因为是集群部署 所以有多个用 分号 隔开\n     */\n    public static final String NAME_SERVER = \"10.33.20.223:9876\";\n    /**\n     * 主题名称 主题一般是服务器设置好 而不能在代码里去新建topic（ 如果没有创建好，生产者往该主题发送消息 会报找不到topic错误）\n     */\n    public static final String TOPIC = \"stock_change\";\n}\n"
  },
  {
    "path": "springboot-rocketmq/src/main/java/cn/abel/queue/controller/PublisherController.java",
    "content": "package cn.abel.queue.controller;\n\nimport cn.abel.queue.config.JmsConfig;\nimport cn.abel.queue.service.ProducerService;\nimport cn.abel.queue.service.ReceiverService;\nimport org.apache.rocketmq.client.producer.SendResult;\nimport org.apache.rocketmq.common.message.Message;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n\n@RestController\n@RequestMapping(\"/publisher\")\npublic class PublisherController {\n    @Autowired\n    private ProducerService producerService;\n    @Autowired\n    private ReceiverService receiverService;\n\n    private List<String> mesList;\n\n    /**\n     * 初始化消息\n     */\n    public PublisherController() {\n        mesList = new ArrayList<>();\n        mesList.add(\"小小\");\n        mesList.add(\"爸爸\");\n        mesList.add(\"妈妈\");\n        mesList.add(\"爷爷\");\n        mesList.add(\"奶奶\");\n\n    }\n\n    @RequestMapping(\"/text/rocketmq\")\n    public Object callback() throws Exception {\n        //总共发送五次消息\n        for (String s : mesList) {\n            //创建生产信息\n            Message message = new Message(JmsConfig.TOPIC, \"testtag\", (\"小小一家人的称谓:\" + s).getBytes());\n            //发送\n            SendResult sendResult = producerService.getProducer().send(message);\n            System.out.println(String.format(\"输出生产者信息={ %s }\",sendResult));\n        }\n        return \"成功\";\n    }\n}\n"
  },
  {
    "path": "springboot-rocketmq/src/main/java/cn/abel/queue/service/ProducerService.java",
    "content": "package cn.abel.queue.service;\n\nimport cn.abel.queue.config.JmsConfig;\nimport org.apache.rocketmq.client.exception.MQClientException;\nimport org.apache.rocketmq.client.producer.DefaultMQProducer;\nimport org.springframework.stereotype.Component;\nimport org.springframework.stereotype.Service;\n\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n\n@Service\n@Component\npublic class ProducerService {\n    private String producerGroup = \"test_producer\";\n    private DefaultMQProducer producer;\n\n    public ProducerService(){\n        //示例生产者\n        producer = new DefaultMQProducer(producerGroup);\n        //不开启vip通道 开通口端口会减2\n        producer.setVipChannelEnabled(false);\n        //绑定name server\n        producer.setNamesrvAddr(JmsConfig.NAME_SERVER);\n        start();\n    }\n    /**\n     * 对象在使用之前必须要调用一次，只能初始化一次\n     */\n    public void start(){\n        try {\n            this.producer.start();\n        } catch (MQClientException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public DefaultMQProducer getProducer(){\n        return this.producer;\n    }\n    /**\n     * 一般在应用上下文，使用上下文监听器，进行关闭\n     */\n    public void shutdown(){\n        this.producer.shutdown();\n    }\n}"
  },
  {
    "path": "springboot-rocketmq/src/main/java/cn/abel/queue/service/ReceiverService.java",
    "content": "package cn.abel.queue.service;\n\nimport cn.abel.queue.config.JmsConfig;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;\nimport org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;\nimport org.apache.rocketmq.client.exception.MQClientException;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.common.message.Message;\nimport org.springframework.stereotype.Service;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@Service\npublic class ReceiverService {\n    /**\n     * 消费者实体对象\n     */\n    private DefaultMQPushConsumer consumer;\n    /**\n     * 消费者组\n     */\n    public static final String CONSUMER_GROUP = \"test_consumer\";\n    /**\n     * 通过构造函数 实例化对象\n     */\n    public ReceiverService() throws MQClientException {\n\n        consumer = new DefaultMQPushConsumer(CONSUMER_GROUP);\n        consumer.setNamesrvAddr(JmsConfig.NAME_SERVER);\n        //消费模式:一个新的订阅组第一次启动从队列的最后位置开始消费 后续再启动接着上次消费的进度开始消费\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n        //订阅主题和 标签（ * 代表所有标签)下信息\n        consumer.subscribe(JmsConfig.TOPIC, \"*\");\n        // //注册消费的监听 并在此监听中消费信息，并返回消费的状态信息\n        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {\n            // msgs中只收集同一个topic，同一个tag，并且key相同的message\n            // 会把不同的消息分别放置到不同的队列中\n            try {\n                for (Message msg : msgs) {\n\n                    //消费者获取消息 这里只输出 不做后面逻辑处理\n                    String body = new String(msg.getBody(), \"utf-8\");\n                    System.out.println(String.format(\"Consumer-获取消息-主题topic为={ %s }, 消费消息为={ %s }\", msg.getTopic(), body));\n                }\n            } catch (UnsupportedEncodingException e) {\n                e.printStackTrace();\n                return ConsumeConcurrentlyStatus.RECONSUME_LATER;\n            }\n            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;\n        });\n\n        consumer.start();\n        System.out.println(\"消费者 启动成功=======\");\n    }\n}\n\n"
  },
  {
    "path": "springboot-rocketmq/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=9666\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200\nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=rocketmq-queue\napplication.main=cn.abel.queue.Application\n\n## LOG\nlogging.file=./logs/rocketmq-queue.log\n\n\n"
  },
  {
    "path": "springboot-rocketmq/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-rocketmq/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>demo</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-rocketmq-ali/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-rocketmq-ali</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.4.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <!--rockermq-->\n        <dependency>\n            <groupId>com.aliyun.openservices</groupId>\n            <artifactId>ons-client</artifactId>\n            <version>1.8.3.Final</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.58</version>\n        </dependency>\n\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.18.1</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/Application.java",
    "content": "package cn.abel.queue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/config/ALiConsumerClient.java",
    "content": "package cn.abel.queue.config;\n\nimport cn.abel.queue.service.MessageHandler;\nimport com.aliyun.openservices.ons.api.MessageListener;\nimport com.aliyun.openservices.ons.api.PropertyKeyConst;\nimport com.aliyun.openservices.ons.api.bean.ConsumerBean;\nimport com.aliyun.openservices.ons.api.bean.Subscription;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * @author yyb\n * @time 2020/3/25\n */\n\n@Configuration\npublic class ALiConsumerClient {\n    private static final Logger logger = LoggerFactory.getLogger(ALiConsumerClient.class);\n    /**\n     * topic tag。\n     */\n    private static final String TOPIC_TAG = \"*\";\n    /**\n     * 消费者线程数。\n     */\n    private static final int CONSUMER_THREAD_COUNT = 10;\n    /**\n     * 重新消费次数。\n     */\n    private static final int RECONSUME_TIMES = 2;\n\n    private MessageHandler handler;\n\n    @Value(\"${ali.rocket.mq.access-key}\")\n    private String accessKey;\n    @Value(\"${ali.rocket.mq.secret-key}\")\n    private String secretKey;\n    @Value(\"${ali.rocket.mq.name-srv-addr}\")\n    private String nameSrvAddr;\n    @Value(\"${ali.rocket.mq.test-topic}\")\n    private String topic;\n    @Value(\"${ali.rocket.mq.test-group-id}\")\n    private String group;\n\n    @Bean(initMethod = \"start\", destroyMethod = \"shutdown\")\n    public ConsumerBean buildConsumer() {\n        ConsumerBean consumerBean = new ConsumerBean();\n        Properties properties = new Properties();\n        properties.setProperty(PropertyKeyConst.AccessKey, accessKey);\n        properties.setProperty(PropertyKeyConst.SecretKey, secretKey);\n        properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, nameSrvAddr);\n        properties.setProperty(PropertyKeyConst.GROUP_ID, group);\n        properties.setProperty(PropertyKeyConst.ConsumeThreadNums, String.valueOf(CONSUMER_THREAD_COUNT));\n        properties.setProperty(PropertyKeyConst.MaxReconsumeTimes, String.valueOf(RECONSUME_TIMES));\n        consumerBean.setProperties(properties);\n\n        Map<Subscription, MessageListener> subscriptionTable = new HashMap<>();\n        Subscription subscription = new Subscription();\n        subscription.setTopic(topic);\n        subscription.setExpression(TOPIC_TAG);\n        subscriptionTable.put(subscription, handler);\n        consumerBean.setSubscriptionTable(subscriptionTable);\n        logger.info(\"初始化rocketMq完成 config:{}\");\n        return consumerBean;\n    }\n\n    @Autowired\n    public ALiConsumerClient(MessageHandler handler) {\n        this.handler = handler;\n    }\n}\n"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/config/ALiMqConfig.java",
    "content": "package cn.abel.queue.config;\n\nimport com.aliyun.openservices.ons.api.PropertyKeyConst;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Properties;\n\n/**\n * @author yyb\n * @time 2020/3/25\n */\n@Component\n@ConfigurationProperties(prefix = \"ali.rocket.mq\")\npublic class ALiMqConfig {\n    private String accessKey;\n    private String secretKey;\n    private String nameSrvAddr;\n    private String testTopic;\n    private String testGroupId;\n    private String testTag;\n\n    public Properties getMqProperties() {\n        Properties properties = new Properties();\n        properties.setProperty(PropertyKeyConst.AccessKey, this.accessKey);\n        properties.setProperty(PropertyKeyConst.SecretKey, this.secretKey);\n        properties.setProperty(PropertyKeyConst.GROUP_ID, testGroupId);\n        properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, this.nameSrvAddr);\n        return properties;\n    }\n\n    public String getAccessKey() {\n        return accessKey;\n    }\n\n    public void setAccessKey(String accessKey) {\n        this.accessKey = accessKey;\n    }\n\n    public String getSecretKey() {\n        return secretKey;\n    }\n\n    public void setSecretKey(String secretKey) {\n        this.secretKey = secretKey;\n    }\n\n    public String getNameSrvAddr() {\n        return nameSrvAddr;\n    }\n\n    public void setNameSrvAddr(String nameSrvAddr) {\n        this.nameSrvAddr = nameSrvAddr;\n    }\n\n    public String getTestTopic() {\n        return testTopic;\n    }\n\n    public void setTestTopic(String testTopic) {\n        this.testTopic = testTopic;\n    }\n\n    public String getTestGroupId() {\n        return testGroupId;\n    }\n\n    public void setTestGroupId(String testGroupId) {\n        this.testGroupId = testGroupId;\n    }\n\n    public String getTestTag() {\n        return testTag;\n    }\n\n    public void setTestTag(String testTag) {\n        this.testTag = testTag;\n    }\n}\n"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/config/ALiProducerClient.java",
    "content": "package cn.abel.queue.config;\n\nimport com.aliyun.openservices.ons.api.bean.ProducerBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author yyb\n * @time 2020/3/25\n */\n@Component\npublic class ALiProducerClient {\n    @Autowired\n    private ALiMqConfig aLiMqConfig;\n\n    @Bean(name = \"producer\", initMethod = \"start\", destroyMethod = \"shutdown\")\n    public ProducerBean build() {\n        ProducerBean bean = new ProducerBean();\n        bean.setProperties(aLiMqConfig.getMqProperties());\n        return bean;\n    }\n\n    @Autowired\n    public ALiProducerClient(ALiMqConfig aLiMqConfig) {\n        this.aLiMqConfig = aLiMqConfig;\n    }\n}"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/service/MessageHandler.java",
    "content": "package cn.abel.queue.service;\n\nimport com.aliyun.openservices.ons.api.Action;\nimport com.aliyun.openservices.ons.api.ConsumeContext;\nimport com.aliyun.openservices.ons.api.Message;\nimport com.aliyun.openservices.ons.api.MessageListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * @author yyb\n * @time 2020/3/25\n */\n@Component\npublic class MessageHandler implements MessageListener {\n    private static final Logger logger = LoggerFactory.getLogger(MessageHandler.class);\n\n    @Override\n    public Action consume(Message message, ConsumeContext consumeContext) {\n        String msgStr = new String(message.getBody(), StandardCharsets.UTF_8);\n        //接收到消息\n        logger.info(\"Receive message msgId:{} retryTimes:{} body:{}\", message.getMsgID(),\n                message.getReconsumeTimes(), msgStr);\n        //提交\n        return Action.CommitMessage;\n    }\n}\n"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/java/cn/abel/queue/service/ProducerService.java",
    "content": "package cn.abel.queue.service;\n\nimport cn.abel.queue.config.ALiMqConfig;\nimport com.alibaba.fastjson.JSON;\nimport com.aliyun.openservices.ons.api.Message;\nimport com.aliyun.openservices.ons.api.OnExceptionContext;\nimport com.aliyun.openservices.ons.api.SendCallback;\nimport com.aliyun.openservices.ons.api.SendResult;\nimport com.aliyun.openservices.ons.api.bean.ProducerBean;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.function.Predicate;\n\n\n/**\n * @author yyb\n * @time 2019/8/13\n */\n\n@Service\npublic class ProducerService {\n    private static final Logger logger = LoggerFactory.getLogger(ProducerService.class);\n\n    @Autowired\n    private ALiMqConfig aLiMqConfig;\n    @Autowired\n    private ProducerBean producer;\n\n\n    /**\n     * 调用此方法 发送消息，o 为自定义的消息体\n     */\n    public void sendMessage(Object o) {\n        Message message = new Message(aLiMqConfig.getStockTopic(), \"test\", JSON.toJSON(o).toString().getBytes(StandardCharsets.UTF_8));\n        //向mq发送消息\n        sendAsync(ProducerBean::isStarted, producer, message);\n    }\n\n    /**\n     * 向阿里云rocket mq发送消息。\n     *\n     * @param predicate 断言\n     * @param bean      发送消息bean\n     * @param message   需要发送的消息\n     */\n    private static void sendAsync(Predicate<ProducerBean> predicate, ProducerBean bean, Message message) {\n        if (predicate.test(bean)) {\n            bean.sendAsync(message, new SendCallback() {\n                @Override\n                public void onSuccess(SendResult sendResult) {\n                    logger.info(\"向mq推送库存消息成功，消息是：{}\", sendResult.toString());\n                }\n                @Override\n                public void onException(OnExceptionContext e) {\n                    logger.error(\"向mq推送库存消息失败，消息id 为 {} 错误是：{}\", e.getMessageId(), e.getException().getMessage());\n                }\n            });\n        } else {\n            logger.error(\"mq库存生产端启动失败！！！消息是：{}\", message.toString());\n        }\n    }\n\n}"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.port=9666\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200\nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=rocketmq-ali-queue\napplication.main=cn.abel.queue.Application\n\n## LOG\nlogging.file=./logs/rocketmq-queue-ali.log\n\n\n# rocket mq\nali.rocket.mq.access-key=xxxxx\nali.rocket.mq.secret-key=xxxxxx\nali.rocket.mq.name-srv-addr=127.0.0.1:9876\nali.rocket.mq.test-topic=mq_test\nali.rocket.mq.test-group-id=test\nali.rocket.mq.test-tag="
  },
  {
    "path": "springboot-rocketmq-ali/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-rocketmq-ali/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-rocketmq-ali</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-shiro/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.abel-shiro</groupId>\n    <artifactId>springboot-shiro</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <start-class>com.unistacks.epp.manager.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-logging</groupId>\n            <artifactId>commons-logging</artifactId>\n            <version>1.2</version>\n        </dependency>\n\n         <!--db-->\n\n\n\n        <!--shiro相关-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n            <version>1.2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.theborakompanioni</groupId>\n            <artifactId>thymeleaf-extras-shiro</artifactId>\n            <version>1.2.1</version>\n        </dependency>\n        <!--log4j12-->\n\n        <dependency>\n            <groupId>org.apache.kafka</groupId>\n            <artifactId>kafka_2.11</artifactId>\n            <version>0.10.1.0</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.slf4j</groupId>\n                    <artifactId>slf4j-log4j12</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/Application.java",
    "content": "package com.us;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/bean/Event.java",
    "content": "package com.us.bean;\n\nimport java.util.Date;\n\n\npublic class Event {\n\tprivate Integer id;\n\tprivate Integer rawEventId;\n\tprivate String host;\n\tprivate String ip;\n\tprivate String source;\n\tprivate String type;\n\tprivate Date startTime;\n\tprivate Date endTime;\n\tprivate String content;\n\tprivate String dataType;\n\tprivate String suggest;\n\tprivate Integer businessSystemId;\n\tprivate Integer departmentId;\n\tprivate String status;\n\tprivate Integer occurCount;\n\tprivate String owner;\n\tprivate Date responsedTime;\n\tprivate String responsedBy;\n\tprivate Date resolvedTime;\n\tprivate String resolvedBy;\n\tprivate Date closedTime;\n\tprivate String closedBy;\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\tpublic Integer getRawEventId() {\n\t\treturn rawEventId;\n\t}\n\tpublic void setRawEventId(Integer rawEventId) {\n\t\tthis.rawEventId = rawEventId;\n\t}\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\tpublic String getIp() {\n\t\treturn ip;\n\t}\n\tpublic void setIp(String ip) {\n\t\tthis.ip = ip;\n\t}\n\tpublic String getSource() {\n\t\treturn source;\n\t}\n\tpublic void setSource(String source) {\n\t\tthis.source = source;\n\t}\n\tpublic String getType() {\n\t\treturn type;\n\t}\n\tpublic void setType(String type) {\n\t\tthis.type = type;\n\t}\n\tpublic Date getStartTime() {\n\t\treturn startTime;\n\t}\n\tpublic void setStartTime(Date startTime) {\n\t\tthis.startTime = startTime;\n\t}\n\tpublic Date getEndTime() {\n\t\treturn endTime;\n\t}\n\tpublic void setEndTime(Date endTime) {\n\t\tthis.endTime = endTime;\n\t}\n\tpublic String getContent() {\n\t\treturn content;\n\t}\n\tpublic void setContent(String content) {\n\t\tthis.content = content;\n\t}\n\tpublic String getDataType() {\n\t\treturn dataType;\n\t}\n\tpublic void setDataType(String dataType) {\n\t\tthis.dataType = dataType;\n\t}\n\tpublic String getSuggest() {\n\t\treturn suggest;\n\t}\n\tpublic void setSuggest(String suggest) {\n\t\tthis.suggest = suggest;\n\t}\n\tpublic Integer getBusinessSystemId() {\n\t\treturn businessSystemId;\n\t}\n\tpublic void setBusinessSystemId(Integer businessSystemId) {\n\t\tthis.businessSystemId = businessSystemId;\n\t}\n\tpublic Integer getDepartmentId() {\n\t\treturn departmentId;\n\t}\n\tpublic void setDepartmentId(Integer departmentId) {\n\t\tthis.departmentId = departmentId;\n\t}\n\tpublic String getStatus() {\n\t\treturn status;\n\t}\n\tpublic void setStatus(String status) {\n\t\tthis.status = status;\n\t}\n\tpublic Integer getOccurCount() {\n\t\treturn occurCount;\n\t}\n\tpublic void setOccurCount(Integer occurCount) {\n\t\tthis.occurCount = occurCount;\n\t}\n\tpublic String getOwner() {\n\t\treturn owner;\n\t}\n\tpublic void setOwner(String owner) {\n\t\tthis.owner = owner;\n\t}\n\tpublic Date getResponsedTime() {\n\t\treturn responsedTime;\n\t}\n\tpublic void setResponsedTime(Date responsedTime) {\n\t\tthis.responsedTime = responsedTime;\n\t}\n\tpublic String getResponsedBy() {\n\t\treturn responsedBy;\n\t}\n\tpublic void setResponsedBy(String responsedBy) {\n\t\tthis.responsedBy = responsedBy;\n\t}\n\tpublic Date getResolvedTime() {\n\t\treturn resolvedTime;\n\t}\n\tpublic void setResolvedTime(Date resolvedTime) {\n\t\tthis.resolvedTime = resolvedTime;\n\t}\n\tpublic String getResolvedBy() {\n\t\treturn resolvedBy;\n\t}\n\tpublic void setResolvedBy(String resolvedBy) {\n\t\tthis.resolvedBy = resolvedBy;\n\t}\n\tpublic Date getClosedTime() {\n\t\treturn closedTime;\n\t}\n\tpublic void setClosedTime(Date closedTime) {\n\t\tthis.closedTime = closedTime;\n\t}\n\tpublic String getClosedBy() {\n\t\treturn closedBy;\n\t}\n\tpublic void setClosedBy(String closedBy) {\n\t\tthis.closedBy = closedBy;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Event{\" +\n\t\t\t\"id=\" + id +\n\t\t\t\", rawEventId=\" + rawEventId +\n\t\t\t\", host=\" + host +\n\t\t\t\", ip=\" + ip +\n\t\t\t\", source=\" + source +\n\t\t\t\", type=\" + type +\n\t\t\t\", startTime=\" + startTime +\n\t\t\t\", endTime=\" + endTime +\n\t\t\t\", content=\" + content +\n\t\t\t\", dataType=\" + dataType +\n\t\t\t\", suggest=\" + suggest +\n\t\t\t\", businessSystemId=\" + businessSystemId +\n\t\t\t\", departmentId=\" + departmentId +\n\t\t\t\", status=\" + status +\n\t\t\t\", occurCount=\" + occurCount +\n\t\t\t\", owner=\" + owner +\n\t\t\t\", responsedTime=\" + responsedTime +\n\t\t\t\", responsedBy=\" + responsedBy +\n\t\t\t\", resolvedTime=\" + resolvedTime +\n\t\t\t\", resolvedBy=\" + resolvedBy +\n\t\t\t\", closedTime=\" + closedTime +\n\t\t\t\", closedBy=\" + closedBy +\n\t\t\t'}';\n\t\t}\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/bean/Permission.java",
    "content": "package com.us.bean;\n\n\npublic class Permission {\n    private Integer id;\n    private String name;\n    private String permissionUrl;\n    private String method;\n    private String description;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPermissionUrl() {\n        return permissionUrl;\n    }\n\n    public void setPermissionUrl(String permissionUrl) {\n        this.permissionUrl = permissionUrl;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"Permission{\" +\n                \"id=\" + id +\n                \", name=\" + name +\n                \", permissionUrl=\" + permissionUrl +\n                \", method=\" + method +\n                \", description=\" + description +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/bean/Role.java",
    "content": "package com.us.bean;\n\n\n\npublic class Role {\n\tprivate Integer id;\n\tprivate String name;\n\tprivate Integer roleLevel;\n\tprivate String description;\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\tpublic Integer getRoleLevel() {\n\t\treturn roleLevel;\n\t}\n\tpublic void setRoleLevel(Integer roleLevel) {\n\t\tthis.roleLevel = roleLevel;\n\t}\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Role{\" +\n\t\t\t\"id=\" + id +\n\t\t\t\", name=\" + name +\n\t\t\t\", roleLevel=\" + roleLevel +\n\t\t\t\", description=\" + description +\n\t\t\t'}';\n\t\t}\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/bean/User.java",
    "content": "package com.us.bean;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport java.util.List;\n\npublic class User   {\n\tprivate Integer id;\n\tprivate String cnname;\n\tprivate String username;\n\n\t@JsonIgnore\n\tprivate String password;\n\tprivate String email;\n\tprivate String telephone;\n\tprivate String mobilePhone;\n\tprivate String wechatId;\n\tprivate String skill;\n\tprivate Integer departmentId;\n\tprivate Integer loginCount;\n\n\tprivate List<Role> roles;\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getCnname() {\n\t\treturn cnname;\n\t}\n\tpublic void setCnname(String cnname) {\n\t\tthis.cnname = cnname;\n\t}\n\tpublic String getUsername() {\n\t\treturn username;\n\t}\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\tpublic String getEmail() {\n\t\treturn email;\n\t}\n\tpublic void setEmail(String email) {\n\t\tthis.email = email;\n\t}\n\tpublic String getTelephone() {\n\t\treturn telephone;\n\t}\n\tpublic void setTelephone(String telephone) {\n\t\tthis.telephone = telephone;\n\t}\n\tpublic String getMobilePhone() {\n\t\treturn mobilePhone;\n\t}\n\tpublic void setMobilePhone(String mobilePhone) {\n\t\tthis.mobilePhone = mobilePhone;\n\t}\n\tpublic String getWechatId() {\n\t\treturn wechatId;\n\t}\n\tpublic void setWechatId(String wechatId) {\n\t\tthis.wechatId = wechatId;\n\t}\n\tpublic String getSkill() {\n\t\treturn skill;\n\t}\n\tpublic void setSkill(String skill) {\n\t\tthis.skill = skill;\n\t}\n\tpublic Integer getDepartmentId() {\n\t\treturn departmentId;\n\t}\n\tpublic void setDepartmentId(Integer departmentId) {\n\t\tthis.departmentId = departmentId;\n\t}\n\tpublic Integer getLoginCount() {\n\t\treturn loginCount;\n\t}\n\tpublic void setLoginCount(Integer loginCount) {\n\t\tthis.loginCount = loginCount;\n\t}\n\n\tpublic List<Role> getRoles() {\n\t\treturn roles;\n\t}\n\n\tpublic void setRoles(List<Role> roles) {\n\t\tthis.roles = roles;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"User{\" +\n\t\t\t\"id=\" + id +\n\t\t\t\", cnname=\" + cnname +\n\t\t\t\", username=\" + username +\n\t\t\t\", password=\" + password +\n\t\t\t\", email=\" + email +\n\t\t\t\", telephone=\" + telephone +\n\t\t\t\", mobilePhone=\" + mobilePhone +\n\t\t\t\", wechatId=\" + wechatId +\n\t\t\t\", skill=\" + skill +\n\t\t\t\", departmentId=\" + departmentId +\n\t\t\t\", loginCount=\" + loginCount +\n\t\t\t'}';\n\t\t}\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/config/DataSourceConfig.java",
    "content": "package com.us.config;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport java.beans.PropertyVetoException;\n\n@Configuration\npublic class DataSourceConfig {\n\t@Autowired\n    private Environment env;\n\t\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"jdbc.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"jdbc.url\"));\n        dataSource.setUser(env.getProperty(\"jdbc.username\"));\n        dataSource.setPassword(env.getProperty(\"jdbc.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n        \n        return dataSource;\n    }\n    \n    \n}\n\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/config/MapperScannerConfig.java",
    "content": "package com.us.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MapperScannerConfig {\n\n\t@Bean\n\tpublic MapperScannerConfigurer mapperScannerConfigurer() {\n\t\tMapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n\t\tmapperScannerConfigurer.setBasePackage(\"**.dao\");\n\t\tmapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n\t\treturn mapperScannerConfigurer;\n\t}\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/config/MyBatisConfig.java",
    "content": "package com.us.config;\n\nimport org.apache.ibatis.plugin.Interceptor;\nimport org.apache.ibatis.type.JdbcType;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\nimport java.util.Properties;\n\n@Configuration\npublic class MyBatisConfig {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Bean(name = \"sqlSessionFactory\")\n\tpublic SqlSessionFactoryBean sqlSessionFactory(\n\t\t\tApplicationContext applicationContext) throws Exception {\n\t\tSqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n\t\tsessionFactory.setDataSource(dataSource);\n\n\t\torg.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();\n\t\tconfiguration.setMapUnderscoreToCamelCase(true);\n\t\tconfiguration.setJdbcTypeForNull(JdbcType.NULL);\n\t\tsessionFactory.setMapperLocations(applicationContext.getResources(\"classpath:mapper/*.xml\"));\n\n\n\t\treturn sessionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/config/TransactionConfig.java",
    "content": "package com.us.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\npublic class TransactionConfig implements TransactionManagementConfigurer{\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Override\n\t@Bean\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n\t\treturn new DataSourceTransactionManager(dataSource);\n    }\n\t\n\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/controller/EventController.java",
    "content": "package com.us.controller;\n\nimport com.us.bean.Event;\nimport com.us.service.EventService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\n\n@RequestMapping(value = \"/events\")\n@RestController\npublic class EventController {\n\t\n\t@Autowired\n\tprivate EventService eventService;\n\t\n\t\n\t@RequestMapping(method = RequestMethod.GET)\n    public List<Event> list(HttpServletRequest request) {\n\t\treturn eventService.getByMap(null);\n    }\n\t\n\t@RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n    public Event detail(@PathVariable Integer id) {\n\t\treturn eventService.getById(id);\n    }\n    \n    @RequestMapping(method = RequestMethod.POST)\n    public Event create(@RequestBody Event event) {\n\t\treturn eventService.create(event);\n    }\n\n    @RequestMapping(method = RequestMethod.PUT)\n    public Event update(@RequestBody Event event) {\n\t\treturn eventService.update(event);\n    }\n    \n    @RequestMapping(value = \"/{id}\", method = RequestMethod.DELETE)\n    public int delete(@PathVariable Integer id) {\n\t\treturn eventService.delete(id);\n    }\n    \n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/controller/LoginController.java",
    "content": "package com.us.controller;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.AuthenticationException;\n\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.subject.Subject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by cdyoue on 2016/10/21.\n * 登陆控制器\n */\n@RestController\npublic class LoginController {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @RequestMapping(value = \"/login\", method = RequestMethod.POST)\n    public String login(\n            @RequestParam(value = \"username\", required = true) String userName,\n            @RequestParam(value = \"password\", required = true) String password,\n            @RequestParam(value = \"rememberMe\", required = true, defaultValue = \"false\") boolean rememberMe\n    ) {\n        logger.info(\"==========\" + userName + password + rememberMe);\n        Subject subject = SecurityUtils.getSubject();\n        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);\n        token.setRememberMe(rememberMe);\n\n        try {\n            subject.login(token);\n        } catch (AuthenticationException e) {\n            e.printStackTrace();\n//            rediect.addFlashAttribute(\"errorText\", \"您的账号或密码输入错误!\");\n            return \"{\\\"Msg\\\":\\\"您的账号或密码输入错误\\\",\\\"state\\\":\\\"failed\\\"}\";\n        }\n        return \"{\\\"Msg\\\":\\\"登陆成功\\\",\\\"state\\\":\\\"success\\\"}\";\n    }\n\n    @RequestMapping(\"/\")\n    @ResponseBody\n    public String index() {\n        return \"no permission\";\n    }\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/controller/UserController.java",
    "content": "package com.us.controller;\n\n\nimport com.us.bean.User;\nimport com.us.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\n\n@RequestMapping(value = \"/users\")\n@RestController\npublic class UserController {\n\t\n\t@Autowired\n\tprivate UserService userService;\n\t\n\t\n\t@RequestMapping(method = RequestMethod.GET)\n    public List<User> list(HttpServletRequest request) {\n\t\treturn userService.getByMap(null);\n    }\n\t\n\t@RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n    public User detail(@PathVariable Integer id) {\n\t\treturn userService.getById(id);\n    }\n    \n    @RequestMapping(method = RequestMethod.POST)\n    public User create(@RequestBody User user) {\n\t\treturn userService.create(user);\n    }\n\n    @RequestMapping(method = RequestMethod.PUT)\n    public User update(@RequestBody User user) {\n\t\treturn userService.update(user);\n    }\n    \n    @RequestMapping(value = \"/{id}\", method = RequestMethod.DELETE)\n    public int delete(@PathVariable Integer id) {\n\t\treturn userService.delete(id);\n    }\n    \n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/dao/EventDao.java",
    "content": "package com.us.dao;\n\nimport com.us.bean.Event;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface EventDao {\n\n\tList<Event> getByMap(Map<String, Object> map);\n\tEvent getById(Integer id);\n\tInteger create(Event event);\n\tint update(Event event);\n\tint delete(Integer id);\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/dao/PermissionDao.java",
    "content": "package com.us.dao;\n\nimport com.us.bean.Permission;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface PermissionDao {\n\n    List<Permission> getByMap(Map<String, Object> map);\n\n    Permission getById(Integer id);\n\n    Integer create(Permission permission);\n\n    int update(Permission permission);\n\n    int delete(Integer id);\n\n    List<Permission> getList();\n\n    List<Permission> getByUserId(Integer userId);\n\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/dao/RoleDao.java",
    "content": "package com.us.dao;\n\n\nimport com.us.bean.Role;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface RoleDao {\n\n\tList<Role> getByMap(Map<String, Object> map);\n\tRole getById(Integer id);\n\tInteger create(Role role);\n\tint update(Role role);\n\tint delete(Integer id);\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/dao/UserDao.java",
    "content": "package com.us.dao;\n\nimport com.us.bean.User;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface UserDao {\n\n\tList<User> getByMap(Map<String, Object> map);\n\tUser getById(Integer id);\n\tInteger create(User user);\n\tint update(User user);\n\tint delete(Integer id);\n\tUser getByUserName(String userName);\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/service/EventService.java",
    "content": "package com.us.service;\n\nimport com.us.bean.Event;\nimport com.us.dao.EventDao;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service\npublic class EventService {\n    @Autowired\n\tprivate EventDao eventDao;\n\t\n\tpublic List<Event> getByMap(Map<String,Object> map) {\n\t    return eventDao.getByMap(map);\n\t}\n\t\n\tpublic Event getById(Integer id) {\n\t\treturn eventDao.getById(id);\n\t}\n\t\n\tpublic Event create(Event event) {\n\t\teventDao.create(event);\n\t\treturn event;\n\t}\n\t\n\tpublic Event update(Event event) {\n\t\teventDao.update(event);\n\t\treturn event;\n\t}\n\t\n\tpublic int delete(Integer id) {\n\t\treturn eventDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/service/PermissionService.java",
    "content": "package com.us.service;\n\nimport com.us.bean.Permission;\nimport com.us.dao.PermissionDao;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service\npublic class PermissionService {\n    @Autowired\n\tprivate PermissionDao permissionDao;\n\t\n\tpublic List<Permission> getByMap(Map<String,Object> map) {\n\t    return permissionDao.getByMap(map);\n\t}\n\t\n\tpublic Permission getById(Integer id) {\n\t\treturn permissionDao.getById(id);\n\t}\n\t\n\tpublic Permission create(Permission permission) {\n\t\tpermissionDao.create(permission);\n\t\treturn permission;\n\t}\n\t\n\tpublic Permission update(Permission permission) {\n\t\tpermissionDao.update(permission);\n\t\treturn permission;\n\t}\n\t\n\tpublic int delete(Integer id) {\n\t\treturn permissionDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/service/RoleService.java",
    "content": "package com.us.service;\n\n\nimport com.us.bean.Role;\nimport com.us.dao.RoleDao;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service\npublic class RoleService {\n    @Autowired\n\tprivate RoleDao roleDao;\n\t\n\tpublic List<Role> getByMap(Map<String,Object> map) {\n\t    return roleDao.getByMap(map);\n\t}\n\t\n\tpublic Role getById(Integer id) {\n\t\treturn roleDao.getById(id);\n\t}\n\t\n\tpublic Role create(Role role) {\n\t\troleDao.create(role);\n\t\treturn role;\n\t}\n\t\n\tpublic Role update(Role role) {\n\t\troleDao.update(role);\n\t\treturn role;\n\t}\n\t\n\tpublic int delete(Integer id) {\n\t\treturn roleDao.delete(id);\n\t}\n    \n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/service/UserService.java",
    "content": "package com.us.service;\n\nimport com.us.bean.User;\nimport com.us.dao.UserDao;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Service\npublic class UserService {\n    @Autowired\n\tprivate UserDao userDao;\n\t\n\tpublic List<User> getByMap(Map<String,Object> map) {\n\t    return userDao.getByMap(map);\n\t}\n\t\n\tpublic User getById(Integer id) {\n\t\treturn userDao.getById(id);\n\t}\n\t\n\tpublic User create(User user) {\n\t\tuserDao.create(user);\n\t\treturn user;\n\t}\n\t\n\tpublic User update(User user) {\n\t\tuserDao.update(user);\n\t\treturn user;\n\t}\n\t\n\tpublic int delete(Integer id) {\n\t\treturn userDao.delete(id);\n\t}\n\n\tpublic User getByUserName(String userName) {\n\t\treturn userDao.getByUserName(userName);\n\t}\n\n}"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/shiro/ShiroConfiguration.java",
    "content": "package com.us.shiro;\n\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.filter.authc.LogoutFilter;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport javax.servlet.Filter;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n\n/**\n * shiro配置类\n * Created by cdyoue on 2016/10/21.\n */\n@Configuration\npublic class ShiroConfiguration {\n    /**\n     * LifecycleBeanPostProcessor，这是个DestructionAwareBeanPostProcessor的子类，\n     * 负责org.apache.shiro.util.Initializable类型bean的生命周期的，初始化和销毁。\n     * 主要是AuthorizingRealm类的子类，以及EhCacheManager类。\n     */\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    /**\n     * HashedCredentialsMatcher，这个类是为了对密码进行编码的，\n     * 防止密码在数据库里明码保存，当然在登陆认证的时候，\n     * 这个类也负责对form里输入的密码进行编码。\n     */\n    @Bean(name = \"hashedCredentialsMatcher\")\n    public HashedCredentialsMatcher hashedCredentialsMatcher() {\n        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();\n        credentialsMatcher.setHashAlgorithmName(\"MD5\");\n        credentialsMatcher.setHashIterations(2);\n        credentialsMatcher.setStoredCredentialsHexEncoded(true);\n        return credentialsMatcher;\n    }\n\n    /**\n     * ShiroRealm，这是个自定义的认证类，继承自AuthorizingRealm，\n     * 负责用户的认证和权限的处理，可以参考JdbcRealm的实现。\n     */\n    @Bean(name = \"shiroRealm\")\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public ShiroRealm shiroRealm() {\n        ShiroRealm realm = new ShiroRealm();\n//        realm.setCredentialsMatcher(hashedCredentialsMatcher());\n        return realm;\n    }\n\n//    /**\n//     * EhCacheManager，缓存管理，用户登陆成功后，把用户信息和权限信息缓存起来，\n//     * 然后每次用户请求时，放入用户的session中，如果不设置这个bean，每个请求都会查询一次数据库。\n//     */\n//    @Bean(name = \"ehCacheManager\")\n//    @DependsOn(\"lifecycleBeanPostProcessor\")\n//    public EhCacheManager ehCacheManager() {\n//        return new EhCacheManager();\n//    }\n\n    /**\n     * SecurityManager，权限管理，这个类组合了登陆，登出，权限，session的处理，是个比较重要的类。\n     * //\n     */\n    @Bean(name = \"securityManager\")\n    public DefaultWebSecurityManager securityManager() {\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroRealm());\n//        securityManager.setCacheManager(ehCacheManager());\n        return securityManager;\n    }\n\n    /**\n     * ShiroFilterFactoryBean，是个factorybean，为了生成ShiroFilter。\n     * 它主要保持了三项数据，securityManager，filters，filterChainDefinitionManager。\n     */\n    @Bean(name = \"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean() {\n        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();\n        shiroFilterFactoryBean.setSecurityManager(securityManager());\n\n        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();\n        LogoutFilter logoutFilter = new LogoutFilter();\n        logoutFilter.setRedirectUrl(\"/login\");\n//        filters.put(\"logout\",null);\n        shiroFilterFactoryBean.setFilters(filters);\n\n        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();\n        filterChainDefinitionManager.put(\"/logout\", \"logout\");\n        filterChainDefinitionManager.put(\"/user/**\", \"authc,roles[ROLE_USER]\");\n        filterChainDefinitionManager.put(\"/events/**\", \"authc,roles[ROLE_ADMIN]\");\n//        filterChainDefinitionManager.put(\"/user/edit/**\", \"authc,perms[user:edit]\");// 这里为了测试，固定写死的值，也可以从数据库或其他配置中读取\n        filterChainDefinitionManager.put(\"/**\", \"anon\");\n        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);\n\n\n        shiroFilterFactoryBean.setSuccessUrl(\"/\");\n        shiroFilterFactoryBean.setUnauthorizedUrl(\"/403\");\n        return shiroFilterFactoryBean;\n    }\n\n    /**\n     * DefaultAdvisorAutoProxyCreator，Spring的一个bean，由Advisor决定对哪些类的方法进行AOP代理。\n     */\n    @Bean\n    @ConditionalOnMissingBean\n    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();\n        defaultAAP.setProxyTargetClass(true);\n        return defaultAAP;\n    }\n\n    /**\n     * AuthorizationAttributeSourceAdvisor，shiro里实现的Advisor类，\n     * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。\n     */\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();\n        aASA.setSecurityManager(securityManager());\n        return aASA;\n    }\n\n\n}\n\n\n\n\n\n"
  },
  {
    "path": "springboot-shiro/src/main/java/com/us/shiro/ShiroRealm.java",
    "content": "package com.us.shiro;\n\nimport com.us.bean.Permission;\nimport com.us.bean.Role;\nimport com.us.bean.User;\nimport com.us.dao.PermissionDao;\nimport com.us.dao.UserDao;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.realm.AuthorizingRealm;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * Created by cdyoue on 2016/10/21.\n */\n\npublic class ShiroRealm extends AuthorizingRealm {\n    private Logger logger =  LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    private UserDao userService;\n    @Autowired\n    private PermissionDao permissionService;\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {\n        logger.info(\"doGetAuthorizationInfo+\"+principalCollection.toString());\n        User user = userService.getByUserName((String) principalCollection.getPrimaryPrincipal());\n\n\n        //把principals放session中 key=userId value=principals\n        SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());\n\n        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\n        //赋予角色\n        for(Role userRole:user.getRoles()){\n            info.addRole(userRole.getName());\n        }\n        //赋予权限\n        for(Permission permission:permissionService.getByUserId(user.getId())){\n//            if(StringUtils.isNotBlank(permission.getPermCode()))\n                info.addStringPermission(permission.getName());\n        }\n\n        //设置登录次数、时间\n//        userService.updateUserLogin(user);\n        return info;\n    }\n\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {\n        logger.info(\"doGetAuthenticationInfo +\"  + authenticationToken.toString());\n\n        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;\n        String userName=token.getUsername();\n        logger.info(userName+token.getPassword());\n\n        User user = userService.getByUserName(token.getUsername());\n        if (user != null) {\n//            byte[] salt = Encodes.decodeHex(user.getSalt());\n//            ShiroUser shiroUser=new ShiroUser(user.getId(), user.getLoginName(), user.getName());\n            //设置用户session\n            Session session = SecurityUtils.getSubject().getSession();\n            session.setAttribute(\"user\", user);\n            return new SimpleAuthenticationInfo(userName,user.getPassword(),getName());\n        } else {\n            return null;\n        }\n//        return null;\n    }\n\n}\n"
  },
  {
    "path": "springboot-shiro/src/main/resources/application.properties",
    "content": "#local\nserver.contextPath=/\nserver.port=8080\n\njdbc.driverClassName=com.mysql.jdbc.Driver\njdbc.url=jdbc:mysql://localhost:3306/epp_manager?useSSL=false&useUnicode=true&characterEncoding=UTF-8\njdbc.username=root\njdbc.password=admin\n\nspring.mvc.view.prefix=/\nspring.mvc.view.suffix=.html\n\nlogging.config=classpath:log4j.properties\n"
  },
  {
    "path": "springboot-shiro/src/main/resources/log4j.properties",
    "content": "#local\r\n# Output pattern : date [thread] priority category - message\r\nlog4j.rootLogger=INFO, Console, R\r\n\r\n#Console\r\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\r\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\nlog4j.appender.R=org.apache.log4j.RollingFileAppender\r\n#/opt/apps/epp-manager/var/logs/epp-manager.log\r\nlog4j.appender.R.File=logs/epp-manager.log\r\nlog4j.appender.R.MaxFileSize=20MB\r\nlog4j.appender.R.MaxBackupIndex=30\r\nlog4j.appender.R.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.R.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\r\n\r\n\r\n#Project defalult level\r\nlog4j.logger.com.us=INFO\r\n\r\n#spring default level\r\nlog4j.logger.org.springframework=INFO\r\nlog4j.logger.org.springframework.jdbc=INFO\r\n\r\n#apache\r\nlog4j.logger.org.apache=INFO\r\n\r\nlog4j.logger.org.activiti=INFO\r\nlog4j.logger.org.activiti.engine.impl.persistence.entity=INFO\r\nlog4j.logger.org.activiti.spring.SpringTransactionInterceptor=ERROR\r\n\r\n#mybatis, debug level to see sql\r\nlog4j.logger.com.us.cmbms.dao=INFO\r\nlog4j.logger.com.us.workflow.dao=INFO\r\n\r\n"
  },
  {
    "path": "springboot-shiro/src/main/resources/mapper/EventDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"com.us.dao.EventDao\">\n    <resultMap id=\"eventMap\" type=\"com.us.bean.Event\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"rawEventId\" column=\"raw_event_id\"/>\n\t\t<result property=\"host\" column=\"host\"/>\n\t\t<result property=\"ip\" column=\"ip\"/>\n\t\t<result property=\"source\" column=\"source\"/>\n\t\t<result property=\"type\" column=\"type\"/>\n\t\t<result property=\"startTime\" column=\"start_time\"/>\n\t\t<result property=\"endTime\" column=\"end_time\"/>\n\t\t<result property=\"content\" column=\"content\"/>\n\t\t<result property=\"dataType\" column=\"data_type\"/>\n\t\t<result property=\"suggest\" column=\"suggest\"/>\n\t\t<result property=\"businessSystemId\" column=\"business_system_id\"/>\n\t\t<result property=\"departmentId\" column=\"department_id\"/>\n\t\t<result property=\"status\" column=\"status\"/>\n\t\t<result property=\"occurCount\" column=\"occur_count\"/>\n\t\t<result property=\"owner\" column=\"owner\"/>\n\t\t<result property=\"responsedTime\" column=\"responsed_time\"/>\n\t\t<result property=\"responsedBy\" column=\"responsed_by\"/>\n\t\t<result property=\"resolvedTime\" column=\"resolved_time\"/>\n\t\t<result property=\"resolvedBy\" column=\"resolved_by\"/>\n\t\t<result property=\"closedTime\" column=\"closed_time\"/>\n\t\t<result property=\"closedBy\" column=\"closed_by\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"rawEventId != null and rawEventId != ''\">\n\t\t\t\tand raw_event_id = #{rawEventId}\n\t\t\t</if>\n\t\t\t<if test=\"host != null and host != ''\">\n\t\t\t\tand host = #{host}\n\t\t\t</if>\n\t\t\t<if test=\"ip != null and ip != ''\">\n\t\t\t\tand ip = #{ip}\n\t\t\t</if>\n\t\t\t<if test=\"source != null and source != ''\">\n\t\t\t\tand source = #{source}\n\t\t\t</if>\n\t\t\t<if test=\"type != null and type != ''\">\n\t\t\t\tand type = #{type}\n\t\t\t</if>\n\t\t\t<if test=\"startTime != null and startTime != ''\">\n\t\t\t\tand start_time = #{startTime}\n\t\t\t</if>\n\t\t\t<if test=\"endTime != null and endTime != ''\">\n\t\t\t\tand end_time = #{endTime}\n\t\t\t</if>\n\t\t\t<if test=\"content != null and content != ''\">\n\t\t\t\tand content = #{content}\n\t\t\t</if>\n\t\t\t<if test=\"dataType != null and dataType != ''\">\n\t\t\t\tand data_type = #{dataType}\n\t\t\t</if>\n\t\t\t<if test=\"suggest != null and suggest != ''\">\n\t\t\t\tand suggest = #{suggest}\n\t\t\t</if>\n\t\t\t<if test=\"businessSystemId != null and businessSystemId != ''\">\n\t\t\t\tand business_system_id = #{businessSystemId}\n\t\t\t</if>\n\t\t\t<if test=\"departmentId != null and departmentId != ''\">\n\t\t\t\tand department_id = #{departmentId}\n\t\t\t</if>\n\t\t\t<if test=\"status != null and status != ''\">\n\t\t\t\tand status = #{status}\n\t\t\t</if>\n\t\t\t<if test=\"occurCount != null and occurCount != ''\">\n\t\t\t\tand occur_count = #{occurCount}\n\t\t\t</if>\n\t\t\t<if test=\"owner != null and owner != ''\">\n\t\t\t\tand owner = #{owner}\n\t\t\t</if>\n\t\t\t<if test=\"responsedTime != null and responsedTime != ''\">\n\t\t\t\tand responsed_time = #{responsedTime}\n\t\t\t</if>\n\t\t\t<if test=\"responsedBy != null and responsedBy != ''\">\n\t\t\t\tand responsed_by = #{responsedBy}\n\t\t\t</if>\n\t\t\t<if test=\"resolvedTime != null and resolvedTime != ''\">\n\t\t\t\tand resolved_time = #{resolvedTime}\n\t\t\t</if>\n\t\t\t<if test=\"resolvedBy != null and resolvedBy != ''\">\n\t\t\t\tand resolved_by = #{resolvedBy}\n\t\t\t</if>\n\t\t\t<if test=\"closedTime != null and closedTime != ''\">\n\t\t\t\tand closed_time = #{closedTime}\n\t\t\t</if>\n\t\t\t<if test=\"closedBy != null and closedBy != ''\">\n\t\t\t\tand closed_by = #{closedBy}\n\t\t\t</if>\n\t\t\t<if test=\"keywords != null and keywords != ''\">\n\t\t\t\tand (\n\t\t\t\thost like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR ip like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR source like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR type like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR content like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR suggest like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR status like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR owner like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR responsed_by like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR resolved_by like CONCAT('%', #{keywords},'%')\n\t\t\t\tOR closed_by like CONCAT('%', #{keywords},'%')\n\t\t\t\t)\n\t\t\t</if>\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"eventMap\">\n    \tSELECT * FROM event\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"eventMap\">\n    \tSELECT * FROM event WHERE id =#{id}\n    </select>\n\n    <insert id=\"create\" parameterType=\"com.us.bean.Event\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO event(\n\t\t\tid,\n\t\t\traw_event_id,\n\t\t\thost,\n\t\t\tip,\n\t\t\tsource,\n\t\t\ttype,\n\t\t\tstart_time,\n\t\t\tend_time,\n\t\t\tcontent,\n\t\t\tdata_type,\n\t\t\tsuggest,\n\t\t\tbusiness_system_id,\n\t\t\tdepartment_id,\n\t\t\tstatus,\n\t\t\toccur_count,\n\t\t\towner,\n\t\t\tresponsed_time,\n\t\t\tresponsed_by,\n\t\t\tresolved_time,\n\t\t\tresolved_by,\n\t\t\tclosed_time,\n\t\t\tclosed_by\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{rawEventId},\n\t\t\t#{host},\n\t\t\t#{ip},\n\t\t\t#{source},\n\t\t\t#{type},\n\t\t\t#{startTime},\n\t\t\t#{endTime},\n\t\t\t#{content},\n\t\t\t#{dataType},\n\t\t\t#{suggest},\n\t\t\t#{businessSystemId},\n\t\t\t#{departmentId},\n\t\t\t#{status},\n\t\t\t#{occurCount},\n\t\t\t#{owner},\n\t\t\t#{responsedTime},\n\t\t\t#{responsedBy},\n\t\t\t#{resolvedTime},\n\t\t\t#{resolvedBy},\n\t\t\t#{closedTime},\n\t\t\t#{closedBy}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"com.us.bean.Event\">\n\t\tUPDATE event SET\n\t\t\traw_event_id = #{rawEventId},\n\t\t\thost = #{host},\n\t\t\tip = #{ip},\n\t\t\tsource = #{source},\n\t\t\ttype = #{type},\n\t\t\tstart_time = #{startTime},\n\t\t\tend_time = #{endTime},\n\t\t\tcontent = #{content},\n\t\t\tdata_type = #{dataType},\n\t\t\tsuggest = #{suggest},\n\t\t\tbusiness_system_id = #{businessSystemId},\n\t\t\tdepartment_id = #{departmentId},\n\t\t\tstatus = #{status},\n\t\t\toccur_count = #{occurCount},\n\t\t\towner = #{owner},\n\t\t\tresponsed_time = #{responsedTime},\n\t\t\tresponsed_by = #{responsedBy},\n\t\t\tresolved_time = #{resolvedTime},\n\t\t\tresolved_by = #{resolvedBy},\n\t\t\tclosed_time = #{closedTime},\n\t\t\tclosed_by = #{closedBy}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM event WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-shiro/src/main/resources/mapper/PermissionDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.dao.PermissionDao\">\n    <resultMap id=\"permissionMap\" type=\"com.us.bean.Permission\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"permissionUrl\" column=\"permission_url\"/>\n\t\t<result property=\"method\" column=\"method\"/>\n\t\t<result property=\"description\" column=\"description\"/>\n\n    </resultMap>\n\n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"permissionUrl != null and permissionUrl != ''\">\n\t\t\t\tand permission_url = #{permissionUrl}\n\t\t\t</if>\n\t\t\t<if test=\"method != null and method != ''\">\n\t\t\t\tand method = #{method}\n\t\t\t</if>\n\t\t\t<if test=\"description != null and description != ''\">\n\t\t\t\tand description = #{description}\n\t\t\t</if>\n\n        </where>\n    </sql>\n\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission\n\t\t<include refid=\"queryCondition\" />\n    </select>\n\n    <select id=\"getById\" parameterType=\"int\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission WHERE id =#{id}\n    </select>\n\n\t<select id=\"getList\"  resultMap=\"permissionMap\">\n\t\tSELECT * from permission\n\t</select>\n\n\t<select id=\"getByUserId\" parameterType=\"int\" resultMap=\"permissionMap\">\n\t\tselect p.*\n\t\tfrom user u\n\t\tLEFT JOIN user_role ur on u.id= ur.User_id\n\t\tLEFT JOIN role r on ur.role_id=r.id\n\t\tLEFT JOIN role_permission rp on rp.role_id=r.id\n\t\tLEFT JOIN permission p on p.id =rp.permission_id\n\t\twhere u.id=#{userId}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"com.us.bean.Permission\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO permission(\n\t\t\tid,\n\t\t\tname,\n\t\t\tpermission_url,\n\t\t    method,\n\t\t\tdescription\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{permissionUrl},\n\t\t    #{method},\n\t\t\t#{description}\n\t\t)\n    </insert>\n\n    <update id=\"update\" parameterType=\"com.us.bean.Permission\">\n\t\tUPDATE permission SET\n\t\t\tname = #{name},\n\t\t\tpermission_url = #{permissionUrl},\n\t\t\tmethod = #{method},\n\t\t\tdescription = #{description}\n\t\tWHERE id = #{id}\n    </update>\n\n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM permission WHERE id = #{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "springboot-shiro/src/main/resources/mapper/RoleDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"com.us.dao.RoleDao\">\n    <resultMap id=\"roleMap\" type=\"com.us.bean.Role\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"roleLevel\" column=\"role_level\"/>\n\t\t<result property=\"description\" column=\"description\"/>\n\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"roleLevel != null and roleLevel != ''\">\n\t\t\t\tand role_level = #{roleLevel}\n\t\t\t</if>\n\t\t\t<if test=\"description != null and description != ''\">\n\t\t\t\tand description = #{description}\n\t\t\t</if>\n\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"roleMap\">\n    \tSELECT * FROM role\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"roleMap\">\n    \tSELECT * FROM role WHERE id =#{id}\n    </select>\n    \n    <insert id=\"create\" parameterType=\"com.us.bean.Role\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO role(\n\t\t\tid,\n\t\t\tname,\n\t\t\trole_level,\n\t\t\tdescription\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{roleLevel},\n\t\t\t#{description}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"com.us.bean.Role\">\n\t\tUPDATE role SET\n\t\t\tname = #{name},\n\t\t\trole_level = #{roleLevel},\n\t\t\tdescription = #{description}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM role WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-shiro/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"com.us.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.us.bean.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"cnname\" column=\"cnname\"/>\n\t\t<result property=\"username\" column=\"username\"/>\n\t\t<result property=\"password\" column=\"password\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"telephone\" column=\"telephone\"/>\n\t\t<result property=\"mobilePhone\" column=\"mobile_phone\"/>\n\t\t<result property=\"wechatId\" column=\"wechat_id\"/>\n\t\t<result property=\"skill\" column=\"skill\"/>\n\t\t<result property=\"departmentId\" column=\"department_id\"/>\n\t\t<result property=\"loginCount\" column=\"login_count\"/>\n\t\t<collection property=\"roles\" ofType=\"com.us.bean.Role\">\n\t\t\t<result column=\"name\" property=\"name\"/>\n\t\t</collection>\n    </resultMap>\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"cnname != null and cnname != ''\">\n\t\t\t\tand cnname = #{cnname}\n\t\t\t</if>\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tand username = #{username}\n\t\t\t</if>\n\t\t\t<if test=\"password != null and password != ''\">\n\t\t\t\tand password = #{password}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"telephone != null and telephone != ''\">\n\t\t\t\tand telephone = #{telephone}\n\t\t\t</if>\n\t\t\t<if test=\"mobilePhone != null and mobilePhone != ''\">\n\t\t\t\tand mobile_phone = #{mobilePhone}\n\t\t\t</if>\n\t\t\t<if test=\"wechatId != null and wechatId != ''\">\n\t\t\t\tand wechat_id = #{wechatId}\n\t\t\t</if>\n\t\t\t<if test=\"skill != null and skill != ''\">\n\t\t\t\tand skill = #{skill}\n\t\t\t</if>\n\t\t\t<if test=\"departmentId != null and departmentId != ''\">\n\t\t\t\tand department_id = #{departmentId}\n\t\t\t</if>\n\t\t\t<if test=\"loginCount != null and loginCount != ''\">\n\t\t\t\tand login_count = #{loginCount}\n\t\t\t</if>\n\t\t\t<if test=\"keywords != null and keywords != ''\">\n\t\t\t\tand (\n\t\t\t\t\tcnname like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR username like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR telephone like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR mobile_phone like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR email like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR skill like CONCAT('%', #{keywords},'%')\n\t\t\t\t\tOR wechat_id like CONCAT('%', #{keywords},'%')\n\t\t\t\t)\n\t\t\t</if>\n        </where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT * FROM user\n\t\t<include refid=\"queryCondition\" />\n    </select>\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n\n\t<select id=\"getByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom user u\n\t\tLEFT JOIN user_role ur on u.id= ur.user_id\n\t\tLEFT JOIN role r on ur.role_id=r.id\n\t\twhere username= #{username}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"com.us.bean.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tcnname,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\temail,\n\t\t\ttelephone,\n\t\t\tmobile_phone,\n\t\t\twechat_id,\n\t\t\tskill,\n\t\t\tdepartment_id,\n\t\t\tlogin_count\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{cnname},\n\t\t\t#{username},\n\t\t\t#{password},\n\t\t\t#{email},\n\t\t\t#{telephone},\n\t\t\t#{mobilePhone},\n\t\t\t#{wechatId},\n\t\t\t#{skill},\n\t\t\t#{departmentId},\n\t\t\t#{loginCount}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"com.us.bean.User\">\n\t\tUPDATE user SET\n\t\t\tcnname = #{cnname},\n\t\t\tusername = #{username},\n\t\t\tpassword = #{password},\n\t\t\temail = #{email},\n\t\t\ttelephone = #{telephone},\n\t\t\tmobile_phone = #{mobilePhone},\n\t\t\twechat_id = #{wechatId},\n\t\t\tskill = #{skill},\n\t\t\tdepartment_id = #{departmentId},\n\t\t\tlogin_count = #{loginCount}\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n    \n</mapper>"
  },
  {
    "path": "springboot-shiro2/README.md",
    "content": "##springboot-shior2\n\n是使用shior 框架调取用户权限服务，进行登录权限验证的例子，其中的用户权限服务没有写，都是用TODO 标示出来了，使用时可以根据各自的用户权限服务进行编码替换\n\nspringboot-shiro2 也是和dubbo 的结合例子是 消费者的示例。\n引入了 abel-user-api 模块"
  },
  {
    "path": "springboot-shiro2/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>cn.abel</groupId>\n        <artifactId>abel-parent</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <groupId>cn.abel</groupId>\n    <artifactId>springboot-shior2</artifactId>\n    <version>1.0.0</version>\n    <packaging>jar</packaging>\n    <description>Spring Boot</description>\n\n    <dependencies>\n        <dependency>\n            <groupId>cn.abel</groupId>\n            <artifactId>abel-util</artifactId>\n            <version>1.0.0-SNAPSHOT</version>\n        </dependency>\n        <!--引入自己的用户权限管理服务-->\n        <dependency>\n            <groupId>cn.abel</groupId>\n            <artifactId>abel-user-api</artifactId>\n            <version>1.0.0-SNAPSHOT</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-quartz</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-collections4</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>dubbo</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n        </dependency>\n        <!--<dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>-->\n\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-quartz</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.mingsoft</groupId>\n            <artifactId>shiro-freemarker-tags</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.fasterxml.jackson.core</groupId>\n                    <artifactId>jackson-annotations</artifactId>\n                </exclusion>\n            </exclusions>\n            <version>2.9.9.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/ShiroRestApplication.java",
    "content": "package cn.abel.rest;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\nimport org.springframework.context.annotation.ImportResource;\n\n/**\n * 无数据库运行\n *\n */\n@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})\n@ImportResource(\"classpath*:META-INF/spring/*.xml\")\npublic class ShiroRestApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ShiroRestApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/config/RedisConfig.java",
    "content": "package cn.abel.rest.config;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport cn.abel.rest.constants.Constants;\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.commons.pool2.impl.GenericObjectPoolConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.CachingConfigurerSupport;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.interceptor.KeyGenerator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.data.redis.cache.RedisCacheConfiguration;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.cache.RedisCacheWriter;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisPassword;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.RedisSerializationContext;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n/**\n * redis缓存配置\n *\n */\n@Configuration\n@EnableCaching\npublic class RedisConfig extends CachingConfigurerSupport {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);\n    /**\n     * serializer\n     */\n    private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer();\n\n    @Value(\"${spring.redis.database}\")\n    private Integer database;\n    @Value(\"${spring.redis.host}\")\n    private String host;\n    @Value(\"${spring.redis.port}\")\n    private Integer port;\n    @Value(\"${spring.redis.password}\")\n    private String password;\n    @Value(\"${spring.redis.lettuce.pool.max-active}\")\n    private Integer maxActive;\n    @Value(\"${spring.redis.lettuce.pool.max-wait}\")\n    private Integer maxWait;\n    @Value(\"${spring.redis.lettuce.pool.max-idle}\")\n    private Integer maxIdle;\n    @Value(\"${spring.redis.lettuce.pool.min-idle}\")\n    private Integer minIdle;\n    @Value(\"${spring.redis.lettuce.shutdown-timeout}\")\n    private Integer timeout;\n\n    /**\n     * 在使用@Cacheable时，如果不指定key，则使用这个默认的key生成器生成的key\n     *\n     * @return\n     */\n    @Override\n    @Bean\n    public KeyGenerator keyGenerator() {\n        return (target, method, params) -> {\n            StringBuilder sb = new StringBuilder();\n            sb.append(target.getClass().getName());\n            sb.append(method.getName());\n            for (Object obj : params) {\n                sb.append(obj.toString());\n            }\n            return sb.toString();\n        };\n    }\n\n    /**\n     * 声明缓存管理器\n     */\n    @Override\n    @Bean\n    public CacheManager cacheManager() {\n        //1. entryTtl: 定义默认的cache time-to-live.\n        //2. disableCachingNullValues: 禁止缓存Null对象. 视需求而定.\n        //3. computePrefixWith: 此处定义了cache key的前缀, 避免公司不同项目之间的key名称冲突.\n        //4. serializeKeysWith, serializeValuesWith: 定义key和value的序列化协议, 同时的hash key和hash value也被定义.\n\n        // 缓存配置\n        RedisCacheConfiguration cacheConfiguration =\n                RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues().computePrefixWith(cacheName -> Constants.REDIS_KEY_PRE.concat(\":\").concat(cacheName).concat(\":\")).entryTtl(Duration.ofDays(Constants.REDIS_TIMEOUT));\n\n        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(2);\n        //redisCacheConfigurationMap.put(Constants.CACHE_NAME_PERMISSION, permissionCacheConfiguration);\n\n        //初始化一个RedisCacheWriter\n        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory());\n\n        RedisSerializationContext.SerializationPair<String> valuePair =\n                RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER);\n        //RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer(new ObjectMapper()));\n        RedisCacheConfiguration defaultCacheConfig =\n                RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(valuePair);\n        //设置默认过期时间是1天\n        defaultCacheConfig.entryTtl(Duration.ofDays(Constants.REDIS_TIMEOUT));\n\n        //初始化RedisCacheManager\n        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig,\n                redisCacheConfigurationMap);\n        cacheManager.afterPropertiesSet();\n        logger.info(\"RedisCacheManager config success\");\n\n        return cacheManager;\n    }\n\n    @Bean(name = \"redisTemplate\")\n    @Primary\n    public RedisTemplate<String, Object> redisTemplate() {\n        return getTemplate(redisConnectionFactory());\n    }\n\n    @Bean(name = \"stringRedisTemplate\")\n    public StringRedisTemplate stringRedisTemplate() {\n        return new StringRedisTemplate(redisConnectionFactory());\n    }\n\n    private RedisConnectionFactory redisConnectionFactory() {\n        return connectionFactory(maxActive, maxIdle, minIdle, maxWait, host, password, timeout, port, database);\n    }\n\n    private RedisConnectionFactory connectionFactory(Integer maxActive,\n                                                     Integer maxIdle,\n                                                     Integer minIdle,\n                                                     Integer maxWait,\n                                                     String host,\n                                                     String password,\n                                                     Integer timeout,\n                                                     Integer port,\n                                                     Integer database) {\n        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();\n        redisStandaloneConfiguration.setHostName(host);\n        redisStandaloneConfiguration.setPort(port);\n        redisStandaloneConfiguration.setDatabase(database);\n        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));\n\n        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();\n        poolConfig.setMaxTotal(maxActive);\n        poolConfig.setMaxIdle(maxIdle);\n        poolConfig.setMinIdle(minIdle);\n        poolConfig.setMaxWaitMillis(maxWait);\n        LettuceClientConfiguration lettucePoolingConfig = LettucePoolingClientConfiguration.builder()\n                //.commandTimeout(Duration.ofSeconds(15))\n                .poolConfig(poolConfig).shutdownTimeout(Duration.ofMillis(timeout)).build();\n        LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration,\n                lettucePoolingConfig);\n        connectionFactory.afterPropertiesSet();\n\n        return connectionFactory;\n    }\n\n    private RedisTemplate<String, Object> getTemplate(RedisConnectionFactory factory) {\n        RedisTemplate template = new RedisTemplate();\n        template.setConnectionFactory(factory);\n        template.setKeySerializer(STRING_SERIALIZER);\n        template.setValueSerializer(jackson2JsonRedisSerializer());\n        //不能用stringSerializer，有地方使用ShiroUser做key，不能转换\n        //template.setHashKeySerializer(STRING_SERIALIZER);\n        //template.setHashKeySerializer(jackson2JsonRedisSerializer());\n\n        template.afterPropertiesSet();\n\n        return template;\n    }\n\n    private RedisSerializer<Object> jackson2JsonRedisSerializer() {\n        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =\n                new Jackson2JsonRedisSerializer<>(Object.class);\n        ObjectMapper objectMapper = new ObjectMapper();\n        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);\n        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);\n        return jackson2JsonRedisSerializer;\n    }\n\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/constants/Constants.java",
    "content": "package cn.abel.rest.constants;\n\n\npublic interface Constants {\n\n    /**\n     * 第三方登录的token。\n     */\n    String THIRD_PARTY_ACCESS_TOKEN_NAME = \"accessToken\";\n\n    /** 用户注册和绑定时的ip */\n    String CLIENT_IP = \"127.0.0.1\";\n    /** redis缓存 key前缀 */\n    String REDIS_KEY_PRE = \"abel-user\";\n    /** 超时时间（天） */\n    long REDIS_TIMEOUT = 10L;\n\n\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/controller/LoginController.java",
    "content": "package cn.abel.rest.controller;\nimport cn.abel.response.ResponseEntity;\nimport cn.abel.rest.shiro.ShiroUser;\nimport cn.abel.user.models.User;\nimport cn.abel.user.service.PermissionService;\nimport cn.abel.user.service.RoleService;\nimport cn.abel.user.service.UserService;\nimport com.alibaba.dubbo.config.annotation.Reference;\nimport com.google.common.collect.Sets;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.subject.Subject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * @author yyb\n * @time 2020/3/6\n */\n@RestController\n@CrossOrigin\n@RequestMapping(\"/\")\npublic class LoginController {\n\n    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);\n\n    @Reference\n    private UserService userService;\n\n\n    /**\n     * @return\n     */\n    @RequestMapping(value = \"/login\", method = RequestMethod.POST)\n    public ResponseEntity login() {\n        //TODO:登录日志。\n        ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();\n        user.setToken(SecurityUtils.getSubject().getSession().getId().toString());\n        return ResponseEntity.ok(user);\n    }\n\n    /**\n     * 获取当前登录人的登录信息，包括拥有的角色、权限等。\n     *\n     * @return\n     */\n    @GetMapping(\"/logininfo\")\n    public ResponseEntity loginInfo() {\n        ShiroUser shiroUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();\n\n        Map<String, Object> map = new HashMap<>();\n        Set<String> permissions = Sets.newHashSet();\n        //TODO 获取当前用户所有的权限和角色\n        User user = userService.getById(shiroUser.getUserId().intValue());\n        map.put(\"roleList\", user.getRoles());\n        map.put(\"permissionList\", permissions);\n        map.put(\"userId\", shiroUser.getUserId());\n        map.put(\"username\", shiroUser.getLoginName());\n\n        return ResponseEntity.ok(map);\n    }\n\n\n    /**\n     * 注销\n     * @return\n     */\n    @PostMapping(\"/logout\")\n    public ResponseEntity logout() {\n        Subject subject = SecurityUtils.getSubject();\n        subject.logout();\n        return ResponseEntity.ok();\n    }\n\n\n}\n\n\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/exception/DefaultErrorController.java",
    "content": "package cn.abel.rest.exception;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.autoconfigure.web.ServerProperties;\nimport org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;\nimport org.springframework.boot.web.servlet.error.DefaultErrorAttributes;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * 404 覆盖默认error处理方法（不设置则在根目录查找error页面）\n *\n */\n@Controller\npublic class DefaultErrorController extends BasicErrorController {\n\n    public DefaultErrorController(ServerProperties serverProperties) {\n        super(new DefaultErrorAttributes(), serverProperties.getError());\n    }\n\n    /**\n     * 覆盖默认的Json响应\n     */\n    @Override\n    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {\n        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));\n        HttpStatus status = getStatus(request);\n\n        //输出自定义的Json格式\n        Map<String, Object> map = new HashMap<>(2);\n        map.put(\"status\", false);\n        map.put(\"msg\", body.get(\"message\"));\n\n        return new ResponseEntity<>(map, status);\n    }\n\n    /**\n     * 覆盖默认的HTML响应\n     */\n    @Override\n    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {\n        //请求的状态\n        HttpStatus status = getStatus(request);\n        response.setStatus(getStatus(request).value());\n\n        Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));\n        ModelAndView modelAndView = resolveErrorView(request, response, status, model);\n        //指定自定义的视图\n        return (modelAndView == null ? new ModelAndView(\"error/error\", model) : modelAndView);\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/exception/DefaultExceptionHandler.java",
    "content": "package cn.abel.rest.exception;\n\nimport cn.abel.exception.ServiceException;\nimport cn.abel.response.ResponseEntity;\nimport org.apache.shiro.authz.UnauthorizedException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.context.request.NativeWebRequest;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.validation.ConstraintViolationException;\n\n/**\n * 统一异常处理\n *\n */\n@ControllerAdvice\npublic class DefaultExceptionHandler {\n\n    /**\n     * logger\n     */\n    private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionHandler.class);\n\n    private static final String ERROR_500 = \"error/500\";\n    private static final String ERROR_403 = \"error/403\";\n    private static final int ARG_ERROR_CODE = 400;\n\n\n    /**\n     * 参数验证异常。\n     *\n     * @param ex\n     * @return\n     */\n    @ResponseBody\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public ResponseEntity handleMethodArgumentNotValidException(\n            HttpServletRequest request,\n            HttpServletResponse response,\n            MethodArgumentNotValidException ex) {\n        String errMsg = null;\n        if (ex.getBindingResult() != null && ex.getBindingResult().hasErrors()) {\n            errMsg = ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage();\n        }\n        return ResponseEntity.error(ARG_ERROR_CODE, errMsg);\n    }\n\n\n    /**\n     * 参数验证异常。\n     *\n     * @param ex\n     * @return\n     */\n    @ResponseBody\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(ConstraintViolationException.class)\n    public ResponseEntity handleConstraintViolationException(\n            HttpServletRequest request,\n            HttpServletResponse response,\n            ConstraintViolationException ex) {\n        String errMsg = ((ConstraintViolationException) ex).getConstraintViolations()\n                                                           .iterator().next().getMessage();\n        return ResponseEntity.error(ARG_ERROR_CODE, errMsg);\n    }\n\n\n    /**\n     * ServiceException异常\n     *\n     * @param exception\n     * @return\n     */\n    @ExceptionHandler({ServiceException.class})\n    @ResponseStatus(HttpStatus.OK)\n    public String processServiceException(Exception exception, Model model) {\n        model.addAttribute(\"exception\", exception.getMessage());\n        logger.error(\"rpc接口调用异常。{}\", exception.getMessage());\n        return ERROR_500;\n    }\n\n    /**\n     * 没有权限 异常\n     * <p/>\n     * 后续根据不同的需求定制即可\n     * 应用到所有@RequestMapping注解的方法，在其抛出UnauthorizedException异常时执行\n     *\n     * @param request\n     * @param e\n     * @return\n     */\n    @ExceptionHandler({UnauthorizedException.class})\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    public String processUnauthorizedException(NativeWebRequest request, Model model, UnauthorizedException e) {\n        model.addAttribute(\"exception\", e.getMessage());\n        logger.error(\"权限异常。{}\", e.getMessage());\n        return ERROR_403;\n    }\n\n    /**\n     * 运行时异常\n     *\n     * @param exception\n     * @return\n     */\n    @ExceptionHandler({RuntimeException.class})\n    @ResponseStatus(HttpStatus.OK)\n    public String processException(RuntimeException exception, Model model) {\n        model.addAttribute(\"exception\", exception.getMessage());\n        logger.error(\"程序异常\", exception);\n        return ERROR_500;\n    }\n\n    /**\n     * Exception异常\n     *\n     * @param exception\n     * @return\n     */\n    @ExceptionHandler({Exception.class})\n    @ResponseStatus(HttpStatus.OK)\n    public String processException(Exception exception, Model model) {\n        model.addAttribute(\"exception\", exception.getMessage());\n        logger.error(\"程序异常\", exception);\n        return ERROR_500;\n        //logger.info(\"自定义异常处理-Exception\");\n        //ModelAndView m = new ModelAndView();\n        //m.addObject(\"exception\", exception.getMessage());\n        //m.setViewName(\"error/500\");\n        //return m;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/freemarker/CustomFreeMarkerView.java",
    "content": "package cn.abel.rest.freemarker;\n\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerView;\n\n/**\n * freemarker全局变量\n *\n * @date 2018/08/12 17:06\n */\npublic class CustomFreeMarkerView extends FreeMarkerView {\n\n    private static final String CONTEXT_PATH = \"base\";\n\n    @Override\n    protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {\n        String scheme = request.getScheme();\n        String serverName = request.getServerName();\n        int port = request.getServerPort();\n        String path = request.getContextPath();\n        String basePath = scheme + \"://\" + serverName + \":\" + port + path;\n        model.put(CONTEXT_PATH, basePath);\n\n        super.exposeHelpers(model, request);\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/freemarker/FreeMarkerConfig.java",
    "content": "package cn.abel.rest.freemarker;\n\nimport javax.annotation.PostConstruct;\n\nimport com.jagregory.shiro.freemarker.ShiroTags;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.view.InternalResourceViewResolver;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;\n\n/**\n * freemarker配置\n *\n * @date 2018/08/13 11:43\n */\n@Configuration\npublic class FreeMarkerConfig {\n\n    @Autowired\n    freemarker.template.Configuration config;\n    @Autowired\n    FreeMarkerViewResolver resolver;\n    @Autowired\n    InternalResourceViewResolver springResolver;\n\n    @PostConstruct\n    public void setSharedVariable() {\n        config.setNumberFormat(\"0.##\");\n        config.setDateFormat(\"yyyy/MM/dd\");\n        config.setDateTimeFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n        //自定义视图变量和方法\n        resolver.setViewClass(CustomFreeMarkerView.class);\n\n        //shiro标签\n        config.setSharedVariable(\"shiro\", new ShiroTags());\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/HttpHeaderSessionManager.java",
    "content": "package cn.abel.rest.shiro;\n\nimport org.apache.shiro.web.servlet.ShiroHttpServletRequest;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.apache.shiro.web.util.WebUtils;\nimport org.springframework.util.StringUtils;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.Serializable;\n\npublic class HttpHeaderSessionManager extends DefaultWebSessionManager {\n    public static final String LOGIN_TOKEN_KEY = \"sid\";\n    private static final String REFERENCED_SESSION_ID_SOURCE = \"header\";\n\n    @Override\n    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {\n        String id = WebUtils.toHttp(request).getHeader(LOGIN_TOKEN_KEY);\n        if (!StringUtils.isEmpty(id)) {\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);\n            return id;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/RedisSessionDao.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.io.Serializable;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport cn.abel.rest.utils.ServletKit;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 重写SessionDAO，实现session的CRUD功能\n *\n * @date 2019/02/22 14:06\n */\npublic class RedisSessionDao extends EnterpriseCacheSessionDAO {\n\n    /** logger */\n    private static final Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);\n\n    private Cache cache() {\n        Cache<Object, Object> cache = getCacheManager().getCache(this.getClass().getName());\n        return cache;\n    }\n\n    /**\n     * 创建session，保存到数据库\n     *\n     * @param session\n     * @return\n     */\n    @Override\n    protected Serializable doCreate(Session session) {\n        Serializable sessionId = super.doCreate(session);\n        cache().put(sessionId.toString(), session);\n        return sessionId;\n    }\n\n    /**\n     * 获取session\n     *\n     * @param sessionId\n     * @return\n     */\n    @Override\n    protected Session doReadSession(Serializable sessionId) {\n        Session session = null;\n        HttpServletRequest request = ServletKit.getRequest();\n        if (request != null) {\n            String uri = request.getServletPath();\n            if (ServletKit.isStaticFile(uri)) {\n                return null;\n            }\n            session = (Session) request.getAttribute(\"session_\" + sessionId);\n        }\n        if (session == null) {\n            session = super.doReadSession(sessionId);\n        }\n        if (session == null) {\n            session = (Session) cache().get(sessionId.toString());\n        }\n        return session;\n    }\n\n    /**\n     * 更新session的最后一次访问时间\n     *\n     * @param session\n     */\n    @Override\n    protected void doUpdate(Session session) {\n        HttpServletRequest request = ServletKit.getRequest();\n        if (request != null) {\n            String uri = request.getServletPath();\n            if (ServletKit.isStaticFile(uri)) {\n                return;\n            }\n        }\n\n        super.doUpdate(session);\n        cache().put(session.getId().toString(), session);\n\n        logger.debug(\"{}\", session.getAttribute(\"shiroUserId\"));\n    }\n\n    /**\n     * 删除session\n     *\n     * @param session\n     */\n    @Override\n    protected void doDelete(Session session) {\n        super.doDelete(session);\n        cache().remove(session.getId().toString());\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ShiroConfig.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport javax.servlet.Filter;\n\nimport cn.abel.rest.shiro.ext.QuartzSessionValidationScheduler;\nimport cn.abel.rest.shiro.credentials.RetryLimitHashedCredentialsMatcher;\nimport cn.abel.rest.shiro.filter.ShiroFormAuthenticationFilter;\nimport cn.abel.rest.shiro.filter.ShiroLogoutFilter;\nimport org.apache.shiro.authc.credential.CredentialsMatcher;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.codec.Base64;\nimport org.apache.shiro.mgt.RememberMeManager;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.realm.Realm;\nimport org.apache.shiro.session.mgt.SessionValidationScheduler;\nimport org.apache.shiro.session.mgt.eis.SessionDAO;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.CookieRememberMeManager;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.Cookie;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.beans.factory.config.MethodInvokingFactoryBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\n\n/**\n * @date 2018/08/07 23:43\n */\n@Configuration\npublic class ShiroConfig {\n    public final static String SHIRO_REALM_NAME = \"shiroRealm\";\n\n    /**\n     * shiro的Web过滤器\n     *\n     * @param securityManager\n     * @return\n     */\n    @Bean(name = \"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {\n        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();\n        bean.setSecurityManager(securityManager);\n\n        //配置鉴权与登出的拦截器。\n        Map<String, Filter> filterMap = new LinkedHashMap<>();\n        filterMap.put(\"authc\", formAuthenticationFilter());\n        filterMap.put(\"logout\", new ShiroLogoutFilter());\n        bean.setFilters(filterMap);\n\n        //配置各路径需要使用的拦截器。\n        //anon表示anonymous。\n        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();\n        filterChainDefinitionMap.put(\"/logout\", \"logout\");\n        filterChainDefinitionMap.put(\"/css/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/js/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/img/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/font/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/fonts/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/images/**\", \"anon\");\n\n        filterChainDefinitionMap.put(\"/**\", \"authc\");\n        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);\n        return bean;\n    }\n\n    /**\n     * 缓存管理器 使用Ehcache实现\n     *\n     * @return\n     */\n    @Bean(name = \"shiroRedisCacheManager\")\n    //@ConditionalOnClass(name = {\"org.apache.shiro.cache.ehcache.EhCacheManager\"})\n    @ConditionalOnMissingBean(name = \"shiroRedisCacheManager\")\n    public CacheManager shiroRedisCacheManager() {\n        //EhCacheManager cacheManager = new EhCacheManager();\n        //cacheManager.setCacheManagerConfigFile(\"classpath:ehcache-shiro.xml\");\n        //return cacheManager;\n        ShiroRedisCacheManager cacheManager = new ShiroRedisCacheManager();\n        return cacheManager;\n    }\n\n    /**\n     * realm\n     *\n     * @return\n     */\n    @Bean\n    public Realm realm() {\n        ShiroRealm shiroRealm = new ShiroRealm();\n        shiroRealm.setName(SHIRO_REALM_NAME);\n        shiroRealm.setCredentialsMatcher(credentialsMatcher());\n        shiroRealm.setCachingEnabled(true);\n\n        //不设置账号缓存，每次登录都实时调用用户服务的登录接口。\n        shiroRealm.setAuthenticationCachingEnabled(false);\n\n        //不设置角色权限缓存，每次登录都从权限服务实时拉取。\n        shiroRealm.setAuthorizationCachingEnabled(false);\n\n        return shiroRealm;\n    }\n\n    /**\n     * 会话验证调度器\n     *\n     * @return\n     */\n    @Bean(name = \"sessionValidationScheduler\")\n    @ConditionalOnClass(name = {\"org.quartz.Scheduler\"})\n    @ConditionalOnMissingBean(SessionValidationScheduler.class)\n    public SessionValidationScheduler sessionValidationScheduler(DefaultWebSessionManager sessionManager) {\n        QuartzSessionValidationScheduler scheduler = new QuartzSessionValidationScheduler(sessionManager);\n        //scheduler.setSessionValidationInterval(1800000);\n        //scheduler.setSessionManager(sessionManager());\n        sessionManager.setSessionValidationSchedulerEnabled(true);\n        sessionManager.setSessionValidationInterval(1800000);\n        sessionManager.setSessionValidationScheduler(scheduler);\n        return scheduler;\n    }\n\n    /**\n     * 会话DAO\n     *\n     * @return\n     */\n    @Bean\n    public SessionDAO sessionDAO() {\n        RedisSessionDao redisSessionDao = new RedisSessionDao();\n        redisSessionDao.setActiveSessionsCacheName(\"shiro-activeSessionCache\");\n        redisSessionDao.setSessionIdGenerator(new UuidSessionIdGenerator());\n        return redisSessionDao;\n    }\n\n    /**\n     * 会话Cookie模板\n     *\n     * @return\n     */\n    @Bean\n    public Cookie sessionIdCookie() {\n        SimpleCookie cookie = new SimpleCookie(\"sid\");\n        cookie.setHttpOnly(true);\n        cookie.setMaxAge(-1);\n        return cookie;\n    }\n\n    /**\n     * rememberMe Cookie\n     *\n     * @return\n     */\n    @Bean\n    public Cookie rememberMeCookie() {\n        SimpleCookie cookie = new SimpleCookie(\"rememberMe\");\n        cookie.setHttpOnly(true);\n        //30天\n        cookie.setMaxAge(2592000);\n        return cookie;\n    }\n\n    /**\n     * 会话管理器\n     *\n     * @return\n     */\n    @Bean\n    public DefaultWebSessionManager sessionManager() {\n        //SessionManager sessionManager = new SessionManager();\n        HttpHeaderSessionManager sessionManager = new HttpHeaderSessionManager();\n        sessionManager.setGlobalSessionTimeout(43200000);\n        sessionManager.setDeleteInvalidSessions(true);\n        //sessionManager.setSessionValidationSchedulerEnabled(true);\n        //sessionManager.setSessionValidationScheduler(sessionValidationScheduler(sessionManager));\n        //sessionManager.setSessionValidationScheduler(sessionValidationScheduler());\n        sessionManager.setSessionDAO(sessionDAO());\n        sessionManager.setSessionIdCookieEnabled(false);\n//        sessionManager.setSessionIdCookie(sessionIdCookie());\n        //去掉URL中的JSESSIONID\n        sessionManager.setSessionIdUrlRewritingEnabled(false);\n        return sessionManager;\n    }\n\n    /**\n     * 安全管理器\n     *\n     * @return\n     */\n    @Bean\n    @DependsOn(\"redisTemplate\")\n    public SecurityManager securityManager() {\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(realm());\n        securityManager.setCacheManager(shiroRedisCacheManager());\n        securityManager.setSessionManager(sessionManager());\n        securityManager.setRememberMeManager(rememberMeManager());\n        return securityManager;\n    }\n\n    /**\n     * rememberMe管理器\n     *\n     * @return\n     */\n    @Bean\n    public RememberMeManager rememberMeManager() {\n        CookieRememberMeManager manager = new CookieRememberMeManager();\n        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度（128 256 512 位）\n        manager.setCipherKey(Base64.decode(\"4AvVhmFLUs0KTA3Kprsdag==\"));\n        manager.setCookie(rememberMeCookie());\n        return manager;\n    }\n\n    /**\n     * 凭证匹配器\n     *\n     * @return\n     */\n    @Bean(name = \"credentialsMatcher\")\n    public CredentialsMatcher credentialsMatcher() {\n        //明文密码\n        //CustomCredentialsMatcher matcher = new CustomCredentialsMatcher();\n        //HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();\n        RetryLimitHashedCredentialsMatcher matcher = new RetryLimitHashedCredentialsMatcher(shiroRedisCacheManager());\n        //matcher.setHashAlgorithmName(\"md5\");//散列算法:这里使用MD5算法;\n        //matcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(\"\"));\n        matcher.setStoredCredentialsHexEncoded(true);\n        return matcher;\n    }\n\n    @Bean\n    public MethodInvokingFactoryBean methodInvokingFactoryBean() {\n        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();\n        factoryBean.setStaticMethod(\"org.apache.shiro.SecurityUtils.setSecurityManager\");\n        factoryBean.setArguments(securityManager());\n        return factoryBean;\n    }\n\n    /**\n     * Shiro生命周期处理器\n     *\n     * @return\n     */\n    @Bean\n    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    public ShiroFormAuthenticationFilter formAuthenticationFilter() {\n        ShiroFormAuthenticationFilter filter = new ShiroFormAuthenticationFilter();\n        filter.setUsernameParam(\"username\");\n        filter.setPasswordParam(\"password\");\n        filter.setRememberMeParam(\"rememberMe\");\n        filter.setLoginUrl(\"/login\");\n        filter.setSuccessUrl(\"/index\");\n        return filter;\n    }\n\n    /**\n     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,\n     * 并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)\n     * 即可实现此功能\n     *\n     * @return\n     */\n    @Bean\n    @DependsOn({\"lifecycleBeanPostProcessor\"})\n    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        advisorAutoProxyCreator.setProxyTargetClass(true);\n        return advisorAutoProxyCreator;\n    }\n\n    /**\n     * 开启shiro aop注解支持.\n     * 使用代理方式;所以需要开启代码支持;\n     * 需要aspectj支持\n     *\n     * @param securityManager\n     * @return\n     */\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {\n        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =\n                new AuthorizationAttributeSourceAdvisor();\n        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);\n        return authorizationAttributeSourceAdvisor;\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ShiroProperty.java",
    "content": "package cn.abel.rest.shiro;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @date 2019/02/26 14:39\n */\n@Configuration\npublic class ShiroProperty {\n\n    @Value(\"${shiro.retryExpireTimeRedis}\")\n    private int shiroRetryExpireTimeRedis;\n\n    @Value(\"${shiro.authorizationExpireTimeRedis}\")\n    private int shiroAuthorizationExpireTimeRedis;\n\n    @Value(\"${shiro.retryMax}\")\n    private int shiroRetryMax;\n\n    @Value(\"${shiro.sessionExpireTimeRedis}\")\n    private Integer shiroSessionExpireTimeRedis;\n\n    public int getShiroRetryExpireTimeRedis() {\n        return shiroRetryExpireTimeRedis;\n    }\n\n    public void setShiroRetryExpireTimeRedis(int shiroRetryExpireTimeRedis) {\n        this.shiroRetryExpireTimeRedis = shiroRetryExpireTimeRedis;\n    }\n\n    public int getShiroAuthorizationExpireTimeRedis() {\n        return shiroAuthorizationExpireTimeRedis;\n    }\n\n    public void setShiroAuthorizationExpireTimeRedis(int shiroAuthorizationExpireTimeRedis) {\n        this.shiroAuthorizationExpireTimeRedis = shiroAuthorizationExpireTimeRedis;\n    }\n\n    public int getShiroRetryMax() {\n        return shiroRetryMax;\n    }\n\n    public void setShiroRetryMax(int shiroRetryMax) {\n        this.shiroRetryMax = shiroRetryMax;\n    }\n\n    public Integer getShiroSessionExpireTimeRedis() {\n        return shiroSessionExpireTimeRedis;\n    }\n\n    public void setShiroSessionExpireTimeRedis(Integer shiroSessionExpireTimeRedis) {\n        this.shiroSessionExpireTimeRedis = shiroSessionExpireTimeRedis;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ShiroRealm.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\n\nimport cn.abel.exception.ServiceException;\nimport cn.abel.user.models.Permission;\nimport cn.abel.user.models.Role;\nimport cn.abel.user.models.User;\nimport cn.abel.user.service.PermissionService;\nimport cn.abel.user.service.RoleService;\nimport cn.abel.user.service.UserService;\nimport com.alibaba.dubbo.config.annotation.Reference;\nimport com.google.common.collect.Sets;\nimport org.apache.commons.collections4.CollectionUtils;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAccount;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.realm.AuthorizingRealm;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n/**\n * @date 2018/08/07 23:48\n */\n@Component\npublic class ShiroRealm extends AuthorizingRealm {\n\n    /**\n     * logger\n     */\n    private static final Logger logger = LoggerFactory.getLogger(ShiroRealm.class);\n\n    @Reference(check = false)\n    private UserService userService;\n\n\n    /**\n     * 登录 认证回调函数,登录时调用\n     *\n     * @param authenticationToken\n     * @return\n     * @throws AuthenticationException\n     */\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)\n            throws AuthenticationException {\n        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;\n        String username = token.getUsername();\n\n        Random random = new Random();\n        Long userId = random.nextLong();\n\n        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配\n        return new SimpleAccount(new ShiroUser(userId, username, username), \"\", getName());\n    }\n\n    /**\n     * 授权 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用\n     *\n     * @param principals\n     * @return\n     */\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n\n        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();\n\n        Set<String> roles = Sets.newHashSet();\n        Set<String> permissions = Sets.newHashSet();\n\n//        try {\n            //TODO 此处需要获取当前用户的所有角色和权限，放入验证器\n            //登录名为超级管理员账号\n//\n//                //获取用户所有角色\n//                User user = userService.getById( shiroUser.getUserId());\n//                if (CollectionUtils.isEmpty(user.getRoles())) {\n//                    return authorizationInfo;\n//                }\n//\n//                for (Role role : user.getRoles()) {\n//                    //停用的角色不查询权限\n//                    roles.add(role.getName());\n//                    List<Permission> permissionList = permissionService.getByMap(role.getId());\n//                    permissionList.forEach(p -> {\n//                        permissions.add(p.getCode());\n//                    });\n//                }\n//        } catch (ServiceException e) {\n//            logger.error(e.getMessage());\n//            return authorizationInfo;\n//        }\n\n        authorizationInfo.setRoles(roles);\n        authorizationInfo.setStringPermissions(permissions);\n\n        return authorizationInfo;\n    }\n\n    @Override\n    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {\n        super.clearCachedAuthorizationInfo(principals);\n        clearAllCache();\n    }\n\n    @Override\n    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {\n        super.clearCachedAuthenticationInfo(principals);\n        clearAllCache();\n    }\n\n    @Override\n    public void clearCache(PrincipalCollection principals) {\n        super.clearCache(principals);\n        clearAllCache();\n    }\n\n    public void clearAllCachedAuthorizationInfo() {\n        if (getAuthorizationCache() != null) {\n            getAuthorizationCache().clear();\n        }\n    }\n\n    public void clearAllCachedAuthenticationInfo() {\n        if (getAuthenticationCache() != null) {\n            getAuthenticationCache().clear();\n        }\n\n    }\n\n    public void clearAllCache() {\n        clearAllCachedAuthenticationInfo();\n        clearAllCachedAuthorizationInfo();\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ShiroRedisCacheManager.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.util.Collection;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport cn.abel.rest.constants.Constants;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.BoundHashOperations;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.stereotype.Component;\n\n/**\n * 实现Shiro的缓存管理器CacheManger接口，将Spring应用缓存管理器注入shiro缓存管理器，这样shiro的缓存都由Spring处理\n *\n * @date 2019/02/21 18:12\n */\n@Component\npublic class ShiroRedisCacheManager implements CacheManager {\n\n    private final static String CACHE_KEY_PREFIX = Constants.REDIS_KEY_PRE + \":shiro:\";\n\n    @Autowired\n    private ShiroProperty shiroProperty;\n\n    @Autowired\n    private RedisTemplate<String, Object> redisTemplate;\n\n    /** 超时时间 */\n    private long expireTime;\n\n    @Override\n    public <K, V> Cache<K, V> getCache(String name) throws CacheException {\n        if (\"passwordRetryCache\".equals(name)) {\n            expireTime = shiroProperty.getShiroRetryExpireTimeRedis();\n        } else {\n            expireTime = shiroProperty.getShiroAuthorizationExpireTimeRedis();\n        }\n        return new ShiroRedisCache<K, V>(CACHE_KEY_PREFIX + name, expireTime);\n    }\n\n    /**\n     * 为shiro量身定做的一个redis cache,为Authorization cache做了特别优化\n     */\n    public class ShiroRedisCache<K, V> implements Cache<K, V> {\n\n        private String cacheKey;\n\n        // 缓存的超时时间，单位为s\n        private long expireTime = 3600;\n\n        public ShiroRedisCache(String cacheKey, long expireTime) {\n            this.cacheKey = cacheKey;\n            this.expireTime = expireTime;\n        }\n\n        @Override\n        public V get(K key) throws CacheException {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n            Object k = hashKey(key);\n            return hash.get(k);\n        }\n\n        @Override\n        public V put(K key, V value) throws CacheException {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n            //超时时间\n            Object k = hashKey(key);\n            hash.put((K) k, value);\n            hash.expire(expireTime, TimeUnit.SECONDS);\n            return value;\n        }\n\n        @Override\n        public V remove(K key) throws CacheException {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n\n            V value = null;\n            try {\n                Object k = hashKey(key);\n                value = hash.get(k);\n                hash.delete(k);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return value;\n        }\n\n        @Override\n        public void clear() throws CacheException {\n            redisTemplate.delete(cacheKey);\n        }\n\n        @Override\n        public int size() {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n            return hash.size().intValue();\n        }\n\n        @Override\n        public Set<K> keys() {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n            return hash.keys();\n        }\n\n        @Override\n        public Collection<V> values() {\n            BoundHashOperations<String, K, V> hash = redisTemplate.boundHashOps(cacheKey);\n            return hash.values();\n        }\n\n        protected Object hashKey(K key) {\n            //此处很重要,如果key是登录凭证,那么这是访问用户的授权缓存;将登录凭证转为user对象,返回user的id属性做为hash key,否则会以user对象做为hash key,这样就不好清除指定用户的缓存了\n            if (key instanceof PrincipalCollection) {\n                PrincipalCollection pc = (PrincipalCollection) key;\n                ShiroUser user = (ShiroUser) pc.getPrimaryPrincipal();\n                return user.getUserId();\n            }\n            return key;\n        }\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ShiroUser.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.io.Serializable;\n\nimport com.google.common.base.Objects;\n\n/**\n * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.\n *\n */\npublic class ShiroUser implements Serializable {\n\n    private static final long serialVersionUID = -1373760761780840081L;\n\n    private Long userId;\n\n    private String loginName;\n\n    private String nickName;\n\n    private String token;\n\n    public Long getUserId() {\n        return userId;\n    }\n\n    public void setUserId(Long userId) {\n        this.userId = userId;\n    }\n\n    public String getLoginName() {\n        return loginName;\n    }\n\n    public void setLoginName(String loginName) {\n        this.loginName = loginName;\n    }\n\n    public void setNickName(String nickName) {\n        this.nickName = nickName;\n    }\n\n    public ShiroUser(Long userId, String loginName, String nickName) {\n        this.userId = userId;\n        this.loginName = loginName;\n        this.nickName = nickName;\n    }\n\n    public String getNickName() {\n        return nickName;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n    /**\n     * 本函数输出将作为默认的<shiro:principal/>输出.\n     */\n    @Override\n    public String toString() {\n        return loginName;\n    }\n\n    /**\n     * 重载hashCode,只计算loginName;\n     */\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(loginName);\n    }\n\n    /**\n     * 重载equals,只计算loginName;\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ShiroUser other = (ShiroUser) obj;\n        if (loginName == null) {\n            if (other.loginName != null) {\n                return false;\n            }\n        } else if (!loginName.equals(other.loginName)) {\n            return false;\n        }\n        return true;\n    }\n\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/UuidSessionIdGenerator.java",
    "content": "package cn.abel.rest.shiro;\n\nimport java.io.Serializable;\nimport java.util.UUID;\n\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.mgt.eis.SessionIdGenerator;\n\n/**\n * 会话ID生成器\n *\n * @date 2018/08/08 11:04\n */\npublic class UuidSessionIdGenerator implements SessionIdGenerator {\n\n    @Override\n    public Serializable generateId(Session session) {\n        return UUID.randomUUID().toString().replace(\"-\", \"\").toUpperCase();\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/credentials/PasswordHelper.java",
    "content": "package cn.abel.rest.shiro.credentials;\n\nimport org.apache.shiro.crypto.hash.SimpleHash;\nimport org.apache.shiro.util.ByteSource;\n\n/**\n * 密码\n *\n */\npublic class PasswordHelper {\n\n    private static String algorithmName = \"md5\";\n    private static int hashIterations = 2;\n\n    public void setAlgorithmName(String algorithmName) {\n        PasswordHelper.algorithmName = algorithmName;\n    }\n\n    public void setHashIterations(int hashIterations) {\n        PasswordHelper.hashIterations = hashIterations;\n    }\n\n    public static String encryptPassword(String userName, String password) {\n        return new SimpleHash(algorithmName, password, ByteSource.Util.bytes(userName), hashIterations).toHex();\n    }\n\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/credentials/RetryLimitHashedCredentialsMatcher.java",
    "content": "package cn.abel.rest.shiro.credentials;\n\nimport java.util.concurrent.atomic.AtomicInteger;\nimport cn.abel.rest.shiro.ShiroUser;\nimport cn.abel.rest.shiro.ShiroProperty;\n\nimport cn.abel.user.service.UserService;\nimport com.alibaba.dubbo.config.annotation.Reference;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.websocket.Session;\n\n/**\n * 登录验证\n */\npublic class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {\n    private static final Logger logger = LoggerFactory.getLogger(RetryLimitHashedCredentialsMatcher.class);\n\n    @Autowired\n    private ShiroProperty shiroProperty;\n    @Reference\n    private UserService userService;\n\n    private Cache<String, AtomicInteger> passwordRetryCache;\n\n    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {\n        passwordRetryCache = cacheManager.getCache(\"passwordRetryCache\");\n    }\n\n    @Override\n    public boolean doCredentialsMatch(AuthenticationToken originToken, AuthenticationInfo info) {\n        ThirdPartySupportedToken token = (ThirdPartySupportedToken) originToken;\n        ShiroUser shiroUser = (ShiroUser) info.getPrincipals().getPrimaryPrincipal();\n\n        //优先使用第三方token进行登录验证。\n        if (StringUtils.isNotBlank(token.getAccessToken())) {\n            Session session = null;\n//            try {\n                //TODO 从用户服务中通过 token 获取 session\n//                session = userService.getSessionByToken(token.getAccessToken());\n//            } catch (ServiceException e) {\n//                throw new ExpiredCredentialsException();\n//            }\n            if (session == null) {\n                throw new ExpiredCredentialsException();\n            }\n            //TODO 从session 中获取用户相关信息，放入shiro 验证对象 shiroUser\n//            shiroUser.setUserId(session.getUser().getProfileId());\n//            shiroUser.setLoginName(session.getCurrentLoginName());\n//            shiroUser.setNickName(session.getUser().getNickName());\n            return true;\n        }\n\n        String username = token.getUsername();\n        String password = String.valueOf(token.getPassword());\n\n        //判断该账号登录重试次数是否超过上限。\n        AtomicInteger retryCount = passwordRetryCache.get(username);\n        if (retryCount != null && retryCount.get() >= shiroProperty.getShiroRetryMax()) {\n            throw new ExcessiveAttemptsException();\n        }\n\n        //TODO 没有token，则调用用户服务的登录接口重新登录 获取 session\n//        Login login = new Login();\n//        login.setIp(Constants.CLIENT_IP);\n//        login.setLoginMode(2);\n//        login.setLoginName(username);\n//        login.setLoginType(3);\n//        login.setPassword(password);\n//        try {\n//            Session session = userService.login(login);\n//            if (session == null) {\n//                logger.error(\"登录失败。username={}\", username);\n//                throw new IncorrectCredentialsException();\n//            }\n//            if (session.getUser().getDeleteFlag() != 1) {\n//                logger.error(\"登录失败。用户已被锁定。username={}\", username);\n//                throw new LockedAccountException();\n//            }\n\n            //登录成功，清空登录次数缓存。\n            if (retryCount != null) {\n                passwordRetryCache.remove(username);\n            }\n            //TODO 将 session 中的用户id 信息放入 shiro 对shiroUser象中\n//            shiroUser.setUserId(session.getUser().getProfileId());\n//            return true;\n//        } catch (ServiceException e) {\n            //TODO 根据登录接口的异常信息判读 失败情况\n//            if (e.getErrorCode() == InfoCode.USER_LOGIN_NOT_EXIST.getStatus()\n//                    || e.getErrorCode() == InfoCode.REQUEST_PARAM_ERROR.getStatus()) {\n//                logger.error(\"登录失败，用户不存在。username={}\", username);\n//                throw new UnknownAccountException();\n//            } else if (e.getErrorCode() == InfoCode.PASSWORD_ERROR.getStatus()) {\n//                //密码错误缓存登录重试次数缓存。\n//                if (retryCount == null) {\n//                    retryCount = new AtomicInteger(0);\n//                }\n//                retryCount.incrementAndGet();\n//                passwordRetryCache.put(username, retryCount);\n//\n//                logger.error(\"登录失败，用户名或密码错误。username={}\", username);\n//                throw new IncorrectCredentialsException();\n//            } else {\n//                logger.error(\"登录失败，msg={}\", e.getMessage());\n//            }\n//        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/credentials/ThirdPartySupportedToken.java",
    "content": "package cn.abel.rest.shiro.credentials;\n\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.springframework.stereotype.Component;\n\n/**\n * 支持第三方登录的shiro token。\n */\npublic class ThirdPartySupportedToken extends UsernamePasswordToken {\n    private String username;\n    private char[] password;\n    private boolean rememberMe = false;\n    private String host;\n\n    /**\n     * 第三方token。\n     */\n    private String accessToken;\n\n    public ThirdPartySupportedToken(\n            String username,\n            String password,\n            String accessToken) {\n        this.username = username;\n        this.password = password != null ? password.toCharArray() : null;\n        this.accessToken = accessToken;\n    }\n\n    @Override\n    public String getUsername() {\n        return this.username;\n    }\n\n    @Override\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    @Override\n    public char[] getPassword() {\n        return this.password;\n    }\n\n    @Override\n    public void setPassword(char[] password) {\n        this.password = password;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return this.getUsername();\n    }\n\n    @Override\n    public Object getCredentials() {\n        return this.getPassword();\n    }\n\n    @Override\n    public String getHost() {\n        return this.host;\n    }\n\n    @Override\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    @Override\n    public boolean isRememberMe() {\n        return this.rememberMe;\n    }\n\n    @Override\n    public void setRememberMe(boolean rememberMe) {\n        this.rememberMe = rememberMe;\n    }\n\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n\n    @Override\n    public void clear() {\n        super.clear();\n        this.accessToken = null;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ext/QuartzSessionValidationJob.java",
    "content": "package cn.abel.rest.shiro.ext;\n\nimport org.apache.shiro.session.mgt.ValidatingSessionManager;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 基于Quartz 2.* 版本的实现\n *\n * @author web\n */\npublic class QuartzSessionValidationJob implements Job {\n\n    /**\n     * Key used to store the session manager in the job data map for this job.\n     */\n    public static final String SESSION_MANAGER_KEY = \"sessionManager\";\n\n    /**--------------------------------------------\n    |    I N S T A N C E   V A R I A B L E S    |\n    ============================================*/\n    private static final Logger log = LoggerFactory.getLogger(QuartzSessionValidationJob.class);\n\n\t/*--------------------------------------------\n\t|         C O N S T R U C T O R S           |\n\t============================================*/\n\n\t/*--------------------------------------------\n\t|  A C C E S S O R S / M O D I F I E R S    |\n\t============================================*/\n\n\t/*--------------------------------------------\n\t|               M E T H O D S               |\n\t============================================*/\n\n    /**\n     * Called when the job is executed by quartz. This method delegates to the <tt>validateSessions()</tt> method on the\n     * associated session manager.\n     *\n     * @param context the Quartz job execution context for this execution.\n     */\n    @Override\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n\n        JobDataMap jobDataMap = context.getMergedJobDataMap();\n        ValidatingSessionManager sessionManager = (ValidatingSessionManager) jobDataMap.get(SESSION_MANAGER_KEY);\n\n        if (log.isDebugEnabled()) {\n            log.debug(\"Executing session validation Quartz job...\");\n        }\n\n        sessionManager.validateSessions();\n\n        if (log.isDebugEnabled()) {\n            log.debug(\"Session validation Quartz job complete.\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/ext/QuartzSessionValidationScheduler.java",
    "content": "package cn.abel.rest.shiro.ext;\n\nimport org.apache.shiro.session.mgt.DefaultSessionManager;\nimport org.apache.shiro.session.mgt.SessionValidationScheduler;\nimport org.apache.shiro.session.mgt.ValidatingSessionManager;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 基于Quartz 2.* 版本的实现\n *\n * @author web\n */\npublic class QuartzSessionValidationScheduler implements SessionValidationScheduler {\n\n    public static final long DEFAULT_SESSION_VALIDATION_INTERVAL =\n            DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;\n    private static final String JOB_NAME = \"SessionValidationJob\";\n    private static final Logger log = LoggerFactory.getLogger(QuartzSessionValidationScheduler.class);\n    private static final String SESSION_MANAGER_KEY = QuartzSessionValidationJob.SESSION_MANAGER_KEY;\n    private Scheduler scheduler;\n    private boolean schedulerImplicitlyCreated = false;\n\n    private boolean enabled = false;\n    private ValidatingSessionManager sessionManager;\n    private long sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;\n\n    public QuartzSessionValidationScheduler() {\n    }\n\n    public QuartzSessionValidationScheduler(ValidatingSessionManager sessionManager) {\n        this.sessionManager = sessionManager;\n    }\n\n    protected Scheduler getScheduler() throws SchedulerException {\n        if (this.scheduler == null) {\n            this.scheduler = StdSchedulerFactory.getDefaultScheduler();\n            this.schedulerImplicitlyCreated = true;\n        }\n        return this.scheduler;\n    }\n\n    public void setScheduler(Scheduler scheduler) {\n        this.scheduler = scheduler;\n    }\n\n    public void setSessionManager(ValidatingSessionManager sessionManager) {\n        this.sessionManager = sessionManager;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public void setSessionValidationInterval(long sessionValidationInterval) {\n        this.sessionValidationInterval = sessionValidationInterval;\n    }\n\n    @Override\n    public void enableSessionValidation() {\n        if (log.isDebugEnabled()) {\n            log.debug(\"Scheduling session validation job using Quartz with session validation interval of [\" + this.sessionValidationInterval + \"]ms...\");\n        }\n\n        try {\n            //<span style=\"color:#ff0000;\">Quartz 2中的实现</span>\n            SimpleTrigger trigger = TriggerBuilder.newTrigger().startNow().withIdentity(JOB_NAME,\n                    Scheduler.DEFAULT_GROUP).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(sessionValidationInterval)).build();\n\n            JobDetail detail = JobBuilder.newJob(QuartzSessionValidationJob.class).withIdentity(JOB_NAME,\n                    Scheduler.DEFAULT_GROUP).build();\n            detail.getJobDataMap().put(SESSION_MANAGER_KEY, this.sessionManager);\n            Scheduler scheduler = getScheduler();\n\n            scheduler.scheduleJob(detail, trigger);\n            if (this.schedulerImplicitlyCreated) {\n                scheduler.start();\n                if (log.isDebugEnabled()) {\n                    log.debug(\"Successfully started implicitly created Quartz Scheduler instance.\");\n                }\n            }\n            this.enabled = true;\n\n            if (log.isDebugEnabled()) {\n                log.debug(\"Session validation job successfully scheduled with Quartz.\");\n            }\n        } catch (SchedulerException e) {\n            if (log.isErrorEnabled()) {\n                log.error(\"Error starting the Quartz session validation job.  Session validation may not occur.\", e);\n            }\n        }\n    }\n\n    @Override\n    public void disableSessionValidation() {\n        if (log.isDebugEnabled()) {\n            log.debug(\"Stopping Quartz session validation job...\");\n        }\n        Scheduler scheduler;\n        try {\n            scheduler = getScheduler();\n            if (scheduler == null) {\n                if (log.isWarnEnabled()) {\n                    log.warn(\"getScheduler() method returned a null Quartz scheduler, which is unexpected.  Please \" +\n                            \"check your configuration and/or implementation.  Returning quietly since there is no \" +\n                            \"validation job to remove (scheduler does not exist).\");\n                }\n\n                return;\n            }\n        } catch (SchedulerException e) {\n            if (log.isWarnEnabled()) {\n                log.warn(\"Unable to acquire Quartz Scheduler.  Ignoring and returning (already stopped?)\", e);\n            }\n            return;\n        }\n        try {\n            scheduler.unscheduleJob(new TriggerKey(\"SessionValidationJob\", \"DEFAULT\"));\n            if (log.isDebugEnabled()) {\n                log.debug(\"Quartz session validation job stopped successfully.\");\n            }\n        } catch (SchedulerException e) {\n            if (log.isDebugEnabled()) {\n                log.debug(\"Could not cleanly remove SessionValidationJob from Quartz scheduler.  Ignoring and \" +\n                        \"stopping.\", e);\n            }\n\n        }\n\n        this.enabled = false;\n\n        if (this.schedulerImplicitlyCreated) {\n            try {\n                scheduler.shutdown();\n            } catch (SchedulerException e) {\n                if (log.isWarnEnabled()) {\n                    log.warn(\"Unable to cleanly shutdown implicitly created Quartz Scheduler instance.\", e);\n                }\n            } finally {\n                setScheduler(null);\n                this.schedulerImplicitlyCreated = false;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/filter/ShiroFormAuthenticationFilter.java",
    "content": "package cn.abel.rest.shiro.filter;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletResponse;\n\nimport cn.abel.code.InfoCode;\nimport cn.abel.response.ResponseEntity;\nimport cn.abel.rest.constants.Constants;\nimport cn.abel.rest.shiro.ShiroUser;\nimport cn.abel.rest.shiro.credentials.ThirdPartySupportedToken;\nimport com.alibaba.fastjson.JSON;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.authc.FormAuthenticationFilter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.MediaType;\n\n/**\n * 登录filter\n *\n */\npublic class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {\n    private static final Logger logger = LoggerFactory.getLogger(ShiroFormAuthenticationFilter.class);\n\n    @Override\n    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {\n        //登录请求用户名和accessToken不能同时为空。\n        if (isLoginRequest(request, response)) {\n            if (StringUtils.isBlank(getUsername(request))\n                    && StringUtils.isBlank(request.getParameter(Constants.THIRD_PARTY_ACCESS_TOKEN_NAME))) {\n                return responseDirectly((HttpServletResponse) response,\n                        ResponseEntity.error(InfoCode.REQUEST_PARAM_ERROR));\n            }\n        }\n        return super.onPreHandle(request, response, mappedValue);\n    }\n\n    /**\n     * 当鉴权失败的时候执行的方法。\n     *\n     * @param request\n     * @param response\n     * @return\n     * @throws Exception\n     */\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {\n        if (isLoginRequest(request, response)) {\n            if (isLoginSubmission(request, response)) {\n                return executeLogin(request, response);\n            }\n            //登录仅限HttpPost方式，其他任何方式是不合法的。\n            return responseDirectly((HttpServletResponse) response, ResponseEntity.error(InfoCode.LOGIN_TYPE_ERROR));\n        }\n        //调用非登录方法时认证失败的情况。\n        return responseDirectly((HttpServletResponse) response, ResponseEntity.error(InfoCode.INVALID_TOKEN));\n    }\n\n    /**\n     * 登录验证失败后执行的方法。\n     *\n     * @param token\n     * @param e\n     * @param request\n     * @param response\n     * @return\n     */\n    @Override\n    protected boolean onLoginFailure(\n            AuthenticationToken token,\n            AuthenticationException e,\n            ServletRequest request,\n            ServletResponse response) {\n        HttpServletResponse resp = (HttpServletResponse) response;\n        if (e instanceof ExcessiveAttemptsException) {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.PASSWORD_ERROR_MORE_THAN));\n        } else if (e instanceof UnknownAccountException) {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.PASSWORD_ERROR));\n        } else if (e instanceof IncorrectCredentialsException) {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.PASSWORD_ERROR));\n        } else if (e instanceof LockedAccountException) {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.USER_PROFILE_LOCK));\n        } else if (e instanceof ExpiredCredentialsException) {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.INVALID_LOGIN));\n        } else {\n            return responseDirectly(resp, ResponseEntity.error(InfoCode.SERVICE_UNAVAILABLE));\n        }\n    }\n\n    /**\n     * 登录成功后执行的方法。\n     *\n     * @param token\n     * @param subject\n     * @param request\n     * @param response\n     * @return\n     * @throws Exception\n     */\n    @Override\n    protected boolean onLoginSuccess(\n            AuthenticationToken token,\n            Subject subject,\n            ServletRequest request,\n            ServletResponse response) throws Exception {\n        ShiroUser user = (ShiroUser) subject.getPrincipal();\n        user.setToken(subject.getSession().getId().toString());\n        return true;\n    }\n\n    /**\n     * 创建包含第三方accessToken的shiro token。\n     *\n     * @param request\n     * @param response\n     * @return\n     */\n    @Override\n    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {\n        String username = getUsername(request);\n        String password = getPassword(request);\n        String accessToken = request.getParameter(Constants.THIRD_PARTY_ACCESS_TOKEN_NAME);\n        //shiro后续流程可能会用到username，所以如果用accessToken登录时赋值username为它的值。\n        if (StringUtils.isBlank(username)) {\n            username = accessToken;\n        }\n        return new ThirdPartySupportedToken(username, password, accessToken);\n    }\n\n    /**\n     * 直接构造HttpResponse，不再执行后续的所有方法。\n     *\n     * @param response\n     * @param entity\n     * @return\n     */\n    private boolean responseDirectly(HttpServletResponse response, ResponseEntity entity) {\n        response.reset();\n        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);\n\n        //设置跨域信息。\n        response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n        response.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n        response.setHeader(\"Access-Control-Allow-Methods\", \"POST, GET, DELETE, PUT, OPTIONS, HEAD\");\n        response.setHeader(\"Access-Control-Max-Age\", \"3600\");\n        response.setHeader(\"Access-Control-Allow-Headers\", \"*\");\n        try {\n            response.getWriter().write(JSON.toJSONString(entity));\n        } catch (IOException e) {\n            logger.error(\"ResponseError ex:{}\", ExceptionUtils.getStackTrace(e));\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/shiro/filter/ShiroLogoutFilter.java",
    "content": "package cn.abel.rest.shiro.filter;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.authc.LogoutFilter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 注销filter\n *\n * @date 2019/02/26 13:32\n */\npublic class ShiroLogoutFilter extends LogoutFilter {\n\n    private static final Logger logger = LoggerFactory.getLogger(ShiroLogoutFilter.class);\n\n    @Override\n    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {\n        Subject subject = getSubject(request, response);\n        subject.logout();\n        return true;\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/utils/ServletKit.java",
    "content": "package cn.abel.rest.utils;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\nimport org.springframework.web.servlet.resource.ResourceUrlProvider;\n\n/**\n * Servlet工具类\n *\n * @date 2019/02/22 14:07\n */\npublic class ServletKit {\n\n    /**\n     * 在任意位置获取Request\n     *\n     * @return\n     */\n    public static HttpServletRequest getRequest() {\n        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n    }\n\n    /**\n     * 判断请求uri是否是静态资源方法\n     *\n     * @param uri\n     * @return\n     */\n    public static boolean isStaticFile(String uri) {\n        ResourceUrlProvider resourceUrlProvider = SpringContextKit.getBean(ResourceUrlProvider.class);\n        String staticUri = resourceUrlProvider.getForLookupPath(uri);\n        return staticUri != null;\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/java/cn/abel/rest/utils/SpringContextKit.java",
    "content": "package cn.abel.rest.utils;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n\n/**\n * 这个类是为了解决在普通类调用service的问题\n *\n * @date 2018/10/24 15:16\n * @content OfflineMessageService offlineMessageService = (OfflineMessageService) SpringContextUtil\n * .getBean(\"offlineMessageService\");\n */\n@Component\npublic class SpringContextKit implements ApplicationContextAware {\n\n    /** Spring应用上下文 */\n    private static ApplicationContext applicationContext;\n\n    /** 下面的这个方法上加了@Override注解，原因是继承ApplicationContextAware接口是必须实现的方法 */\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        SpringContextKit.applicationContext = applicationContext;\n    }\n\n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n\n    public static Object getBean(String name) throws BeansException {\n        return applicationContext.getBean(name);\n    }\n\n    public static Object getBean(String name, Class requiredType) throws BeansException {\n\n        return applicationContext.getBean(name, requiredType);\n    }\n\n    public static <T> T getBean(Class<T> clazz) throws BeansException {\n        return applicationContext.getBean(clazz);\n    }\n\n    public static boolean containsBean(String name) {\n        return applicationContext.containsBean(name);\n    }\n\n    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {\n        return applicationContext.isSingleton(name);\n    }\n\n    public static Class getType(String name) throws NoSuchBeanDefinitionException {\n        return applicationContext.getType(name);\n    }\n\n    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {\n        return applicationContext.getAliases(name);\n    }\n}"
  },
  {
    "path": "springboot-shiro2/src/main/resources/META-INF/spring/consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"${dubbo.application.name}\" owner=\"abel\" organization=\"abel\" logger=\"slf4j\"/>\n\n    <dubbo:registry protocol=\"zookeeper\" address=\"${dubbo.registry.address}\" file=\"false\" client=\"curator\"\n                    group=\"${dubbo.registry.group}\" version=\"${dubbo.registry.version}\"/>\n\n    <dubbo:annotation package=\"${dubbo.annotation.package}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"${dubbo.protocol.port}\" accesslog=\"${dubbo.log.file}\"/>\n\n    <dubbo:consumer check=\"false\" loadbalance=\"roundrobin\" retries=\"0\" timeout=\"10000\"/>\n\n\n\n    <dubbo:reference id=\"roleService\" interface=\"cn.abel.user.service.UserService\" protocol=\"dubbo\"\n                     timeout=\"300000\" check=\"false\"/>\n\n</beans>"
  },
  {
    "path": "springboot-shiro2/src/main/resources/dev/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.servlet.context-path=/shiro\nserver.port=9738\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200\nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-shiro\napplication.main=cn.abel.rest.ShiroRestApplication\n\n## LOG\nlogging.file=./logs/springboot-shiro.log\n\n## dubbo \\u914D\\u7F6E\ndubbo.application.name=springboot-shiro\ndubbo.registry.group=abel\n#dubbo.registry.address=127.0.0.1:2181\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.version=1.0.0\ndubbo.protocol.port=13182\ndubbo.annotation.package=cn.abel.rest\ndubbo.log.file=./logs/springboot-shiro-dubbo.log\n\n## spring cache\n#\\u7F13\\u5B58\\u7684\\u540D\\u79F0\\u96C6\\u5408\\uFF0C\\u591A\\u4E2A\\u91C7\\u7528\\u9017\\u53F7\\u5206\\u5272\n#spring.cache.cache-names=admin,role\n#\\u7F13\\u5B58\\u7684\\u7C7B\\u578B\\uFF0C\\u5B98\\u65B9\\u63D0\\u4F9B\\u4E86\\u5F88\\u591A\\uFF0C\\u8FD9\\u91CC\\u6211\\u4EEC\\u586B\\u5199redis\nspring.cache.type=redis\n#\\u662F\\u5426\\u7F13\\u5B58null\\u6570\\u636E\\uFF0C\\u9ED8\\u8BA4\\u662Ffalse\n#spring.cache.redis.cache-null-values=false\n#redis\\u4E2D\\u7F13\\u5B58\\u8D85\\u65F6\\u7684\\u65F6\\u95F4\\uFF0C\\u9ED8\\u8BA460000ms\n#spring.cache.redis.time-to-live=60000\n#\\u7F13\\u5B58\\u6570\\u636Ekey\\u662F\\u5426\\u4F7F\\u7528\\u524D\\u7F00\\uFF0C\\u9ED8\\u8BA4\\u662Ftrue\n#spring.cache.redis.use-key-prefix=true\n\n## redis \\u914D\\u7F6E\n# Redis\\u6570\\u636E\\u5E93\\u7D22\\u5F15\nspring.redis.database=3\n# Redis\\u670D\\u52A1\\u5668\\u5730\\u5740\nspring.redis.host=127.0.0.1\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u7AEF\\u53E3\nspring.redis.port=6379\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u5BC6\\u7801\\uFF08\\u9ED8\\u8BA4\\u4E3A\\u7A7A\\uFF09\nspring.redis.password=\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-active=100\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u963B\\u585E\\u7B49\\u5F85\\u65F6\\u95F4\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-wait=1000\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5927\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.max-idle=50\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.min-idle=0\n# \\u8FDE\\u63A5\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.redis.lettuce.shutdown-timeout=0\n\n## view\\u914D\\u7F6E\n# FreeMarker\\u914D\\u7F6E\n# \\u662F\\u5426\\u5F00\\u542F\\u6A21\\u677F\\u7F13\\u5B58\nspring.freemarker.cache=false\n# \\u7F16\\u7801\\u683C\\u5F0F\nspring.freemarker.charset=UTF-8\n# \\u6A21\\u677F\\u7684\\u5A92\\u4F53\\u7C7B\\u578B\\u8BBE\\u7F6E\nspring.freemarker.content-type=text/html\n# \\u524D\\u7F00\\u8BBE\\u7F6E \\u9ED8\\u8BA4\\u4E3A \"\"\nspring.freemarker.prefix=\n# \\u540E\\u7F00\\u8BBE\\u7F6E \\u9ED8\\u8BA4\\u4E3A .ftl\nspring.freemarker.suffix=.ftl\n#\n#spring.freemarker.viewClass=com.yekai.demo.admin.freemarker.CustomFreeMarkerView\n#\nspring.freemarker.expose-request-attributes=true\nspring.freemarker.expose-session-attributes=true\n# \\u5F00\\u542F\\u5B8F\\u652F\\u6301\nspring.freemarker.expose-spring-macro-helpers=true\n# ftl\\u4E2D\\u83B7\\u53D6request\nspring.freemarker.request-context-attribute=request\n\n#\\u767B\\u5F55\\u91CD\\u8BD5\\u6B21\\u6570\nshiro.retryMax=5\n#\\u767B\\u5F55\\u5931\\u8D25\\u9501\\u5B9A\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.retryExpireTimeRedis=900\n#\\u6388\\u6743\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.authorizationExpireTimeRedis=3600\n#session\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.sessionExpireTimeRedis=3600\n\n"
  },
  {
    "path": "springboot-shiro2/src/main/resources/dev/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        dev                           #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-shiro2/src/main/resources/dev/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-shiro</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"INFO\"/>\n    <logger name=\"java.sql.Connection\" level=\"INFO\"/>\n    <logger name=\"java.sql.Statement\" level=\"INFO\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"INFO\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-shiro2/src/main/resources/local/application.properties",
    "content": "## tomcat\\u914D\\u7F6E\nserver.servlet.context-path=/shiro\nserver.port=9738\n#server.tomcat.maxHttpHeaderSize=8192\nserver.tomcat.uri-encoding=UTF-8\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\nspring.messages.encoding=UTF-8\n# tomcat\\u6700\\u5927\\u7EBF\\u7A0B\\u6570\\uFF0C\\u9ED8\\u8BA4\\u4E3A200  \nserver.tomcat.max-threads=800\n# session\\u6700\\u5927\\u8D85\\u65F6\\u65F6\\u95F4(\\u5206\\u949F)\\uFF0C\\u9ED8\\u8BA4\\u4E3A30\nserver.session-timeout=60\n\n## spring \\u914D\\u7F6E\nspring.application.name=springboot-shiro\napplication.main=cn.abel.rest.ShiroRestApplication\n\n## LOG\nlogging.file=./logs/springboot-shiro.log\n\n## dubbo \\u914D\\u7F6E\ndubbo.application.name=springboot-shiro\ndubbo.registry.group=abel\n#dubbo.registry.address=127.0.0.1:2181\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.version=1.0.0\ndubbo.protocol.port=13182\ndubbo.annotation.package=cn.abel.rest\ndubbo.log.file=./logs/springboot-shiro-dubbo.log\n\n## spring cache\n#\\u7F13\\u5B58\\u7684\\u540D\\u79F0\\u96C6\\u5408\\uFF0C\\u591A\\u4E2A\\u91C7\\u7528\\u9017\\u53F7\\u5206\\u5272\n#spring.cache.cache-names=admin,role\n#\\u7F13\\u5B58\\u7684\\u7C7B\\u578B\\uFF0C\\u5B98\\u65B9\\u63D0\\u4F9B\\u4E86\\u5F88\\u591A\\uFF0C\\u8FD9\\u91CC\\u6211\\u4EEC\\u586B\\u5199redis\nspring.cache.type=redis\n#\\u662F\\u5426\\u7F13\\u5B58null\\u6570\\u636E\\uFF0C\\u9ED8\\u8BA4\\u662Ffalse\n#spring.cache.redis.cache-null-values=false\n#redis\\u4E2D\\u7F13\\u5B58\\u8D85\\u65F6\\u7684\\u65F6\\u95F4\\uFF0C\\u9ED8\\u8BA460000ms\n#spring.cache.redis.time-to-live=60000\n#\\u7F13\\u5B58\\u6570\\u636Ekey\\u662F\\u5426\\u4F7F\\u7528\\u524D\\u7F00\\uFF0C\\u9ED8\\u8BA4\\u662Ftrue\n#spring.cache.redis.use-key-prefix=true\n\n## redis \\u914D\\u7F6E\n# Redis\\u6570\\u636E\\u5E93\\u7D22\\u5F15\nspring.redis.database=3\n# Redis\\u670D\\u52A1\\u5668\\u5730\\u5740\nspring.redis.host=127.0.0.1\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u7AEF\\u53E3\nspring.redis.port=6379\n# Redis\\u670D\\u52A1\\u5668\\u8FDE\\u63A5\\u5BC6\\u7801\\uFF08\\u9ED8\\u8BA4\\u4E3A\\u7A7A\\uFF09\nspring.redis.password=\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u8FDE\\u63A5\\u6570\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-active=100\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u963B\\u585E\\u7B49\\u5F85\\u65F6\\u95F4\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09\nspring.redis.lettuce.pool.max-wait=1000\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5927\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.max-idle=50\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5\nspring.redis.lettuce.pool.min-idle=0\n# \\u8FDE\\u63A5\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u6BEB\\u79D2\\uFF09\nspring.redis.lettuce.shutdown-timeout=0\n\n## view\\u914D\\u7F6E\n# FreeMarker\\u914D\\u7F6E\n# \\u662F\\u5426\\u5F00\\u542F\\u6A21\\u677F\\u7F13\\u5B58\nspring.freemarker.cache=false\n# \\u7F16\\u7801\\u683C\\u5F0F\nspring.freemarker.charset=UTF-8\n# \\u6A21\\u677F\\u7684\\u5A92\\u4F53\\u7C7B\\u578B\\u8BBE\\u7F6E\nspring.freemarker.content-type=text/html\n# \\u524D\\u7F00\\u8BBE\\u7F6E \\u9ED8\\u8BA4\\u4E3A \"\"\nspring.freemarker.prefix=\n# \\u540E\\u7F00\\u8BBE\\u7F6E \\u9ED8\\u8BA4\\u4E3A .ftl\nspring.freemarker.suffix=.ftl\n#\n#spring.freemarker.viewClass=com.yekai.demo.admin.freemarker.CustomFreeMarkerView\n#\nspring.freemarker.expose-request-attributes=true\nspring.freemarker.expose-session-attributes=true\n# \\u5F00\\u542F\\u5B8F\\u652F\\u6301\nspring.freemarker.expose-spring-macro-helpers=true\n# ftl\\u4E2D\\u83B7\\u53D6request\nspring.freemarker.request-context-attribute=request\n\n#\\u767B\\u5F55\\u91CD\\u8BD5\\u6B21\\u6570\nshiro.retryMax=5\n#\\u767B\\u5F55\\u5931\\u8D25\\u9501\\u5B9A\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.retryExpireTimeRedis=900\n#\\u6388\\u6743\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.authorizationExpireTimeRedis=3600\n#session\\u8D85\\u65F6\\u65F6\\u95F4\\uFF08\\u79D2\\uFF09\nshiro.sessionExpireTimeRedis=3600\n\n"
  },
  {
    "path": "springboot-shiro2/src/main/resources/local/banner.txt",
    "content": "########################################################\n#                                                      #\n#                        local                         #\n#                                                      #\n########################################################"
  },
  {
    "path": "springboot-shiro2/src/main/resources/local/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>springboot-shiro</contextName>\n\n    <!-- 控制台输入日志信息 -->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <!-- 当日日志归档文件 -->\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--过期日志转存的文件名格式 -->\n            <FileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</FileNamePattern>\n            <!-- 日志保留天数 -->\n            <MaxHistory>60</MaxHistory>\n        </rollingPolicy>\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符 -->\n            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%method - %msg%n</Pattern>\n        </layout>\n    </appender>\n\n    <!--<logger name=\"com.apache.ibatis\" level=\"TRACE\"/>-->\n    <logger name=\"com.apache.ibatis\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Connection\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.Statement\" level=\"DEBUG\"/>\n    <logger name=\"java.sql.PreparedStatement\" level=\"DEBUG\"/>\n\n    <!-- com.alibaba.dubbo是dubbo服务的包，在info以下的级别会产生大量的启动日志，调成WARN减少日志输出 -->\n    <logger name=\"com.alibaba.dubbo\" level=\"INFO\"/>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"FILE\"/>\n        <appender-ref ref=\"CONSOLE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "springboot-springCloud/config/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>config</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-config-server</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-eureka</artifactId>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-springCloud/config/src/main/java/com/abel/ConfigApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.config.server.EnableConfigServer;\nimport org.springframework.cloud.netflix.eureka.EnableEurekaClient;\n\n/**\n * Created by yangyibo on 2018/6/27.\n * 配置模块\n */\n@SpringBootApplication\n//开启配置服务器的支持\n@EnableConfigServer\n//开启Eureka server 作为客户端的支持\n@EnableEurekaClient\npublic class ConfigApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(ConfigApplication.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/config/src/main/resources/application.yml",
    "content": "spring:\n  cloud:\n    config:\n      server:\n        native:\n          search-locations: classpath:/config #配置其他所需的配置文件的路径\n\nserver:\n  port: 8888\n"
  },
  {
    "path": "springboot-springCloud/config/src/main/resources/bootstrap.yml",
    "content": "spring:\n  application:\n    name: config #在Eureka server 注册的服务名为config\n  profiles:\n    active: native # 配置服务器使用本地配置（默认为git 配置）\n\neureka:\n  instance:\n    non-secure-port: ${server.port:8888} #非ssl 端口，若环境变量中server.port有值，则使用环境变量的值，没有则使用8080\n    metadata-map:\n      instanceId: ${spring.application.name}:${random.value} #配置在Eureka server 的实例id\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ #Eureka 客户端设置的 Eureka server 地址"
  },
  {
    "path": "springboot-springCloud/config/src/main/resources/config/person.yml",
    "content": "spring:\n  jpa:\n    database: HSQL "
  },
  {
    "path": "springboot-springCloud/config/src/main/resources/config/some.yml",
    "content": "my:\n  message: Message from Development\n"
  },
  {
    "path": "springboot-springCloud/config/target/classes/application.yml",
    "content": "spring:\n  cloud:\n    config:\n      server:\n        native:\n          search-locations: classpath:/config #配置其他所需的配置文件的路径\n\nserver:\n  port: 8888\n"
  },
  {
    "path": "springboot-springCloud/config/target/classes/bootstrap.yml",
    "content": "spring:\n  application:\n    name: config #在Eureka server 注册的服务名为config\n  profiles:\n    active: native # 配置服务器使用本地配置（默认为git 配置）\n\neureka:\n  instance:\n    non-secure-port: ${server.port:8888} #非ssl 端口，若环境变量中server.port有值，则使用环境变量的值，没有则使用8080\n    metadata-map:\n      instanceId: ${spring.application.name}:${random.value} #配置在Eureka server 的实例id\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ #Eureka 客户端设置的 Eureka server 地址"
  },
  {
    "path": "springboot-springCloud/config/target/classes/config/person.yml",
    "content": "spring:\n  jpa:\n    database: HSQL "
  },
  {
    "path": "springboot-springCloud/config/target/classes/config/some.yml",
    "content": "my:\n  message: Message from Development\n"
  },
  {
    "path": "springboot-springCloud/discovery/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <!--服务发现-->\n    <artifactId>discovery</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-eureka-server</artifactId>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-springCloud/discovery/src/main/java/com/abel/DiscoveryApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;\n\n/**\n * Created by yangyibo on 2018/6/27.\n * 服务发现 一个常规的springboot 项目，只需要通过 @EnableEurekaServer 注解开启对EurekaServer 的支持即可\n */\n@SpringBootApplication\n@EnableEurekaServer\npublic class DiscoveryApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(DiscoveryApplication.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/discovery/src/main/resources/application.yml",
    "content": "#云计算环境下习惯使用YAML 配置此处我们也是用YAML 配置\nserver:\n  port: 8761\n\neureka:\n  instance:\n      #当前Eureka Server 的hostname 为 localhost\n    hostname: localhost\n      #当前服务不需要到Eureka Server  上注册\n  client:\n    register-with-eureka: false\n    fetch-registry: false\n"
  },
  {
    "path": "springboot-springCloud/discovery/target/classes/application.yml",
    "content": "#云计算环境下习惯使用YAML 配置此处我们也是用YAML 配置\nserver:\n  port: 8761\n\neureka:\n  instance:\n      #当前Eureka Server 的hostname 为 localhost\n    hostname: localhost\n      #当前服务不需要到Eureka Server  上注册\n  client:\n    register-with-eureka: false\n    fetch-registry: false\n"
  },
  {
    "path": "springboot-springCloud/monitor/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>monitor</artifactId>\n    <packaging>jar</packaging>\n\n    <name>monitor</name>\n    <description>Turbine and Hystrix Dashboard</description>\n\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-turbine</artifactId>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>com.spotify</groupId>\n                <artifactId>docker-maven-plugin</artifactId>\n                <configuration>\n                    <imageName>${project.name}:${project.version}</imageName>\n                    <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>\n                    <skipDockerBuild>false</skipDockerBuild>\n                    <resources>\n                        <resource>\n                            <directory>${project.build.directory}</directory>\n                            <include>${project.build.finalName}.jar</include>\n                        </resource>\n                    </resources>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "springboot-springCloud/monitor/src/main/java/com/abel/MonitorApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.netflix.eureka.EnableEurekaClient;\nimport org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;\nimport org.springframework.cloud.netflix.turbine.EnableTurbine;\n/**\n * Created by yangyibo on 2018/6/29.\n */\n@SpringBootApplication\n@EnableEurekaClient\n@EnableHystrixDashboard\n@EnableTurbine\npublic class MonitorApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MonitorApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/monitor/src/main/resources/application.yml",
    "content": "server:\n  port: 8989\n\n"
  },
  {
    "path": "springboot-springCloud/monitor/src/main/resources/bootstrap.yml",
    "content": "spring:\n  application:\n    name: monitor\n\neureka:\n  instance:\n    nonSecurePort: ${server.port:8989}\n  client:\n    serviceUrl:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/monitor/target/classes/application.yml",
    "content": "server:\n  port: 8989\n\n"
  },
  {
    "path": "springboot-springCloud/monitor/target/classes/bootstrap.yml",
    "content": "spring:\n  application:\n    name: monitor\n\neureka:\n  instance:\n    nonSecurePort: ${server.port:8989}\n  client:\n    serviceUrl:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/person/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <artifactId>person</artifactId>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-config-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-eureka</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hsqldb</groupId>\n            <artifactId>hsqldb</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n            <version>9.1-901-1.jdbc4</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-springCloud/person/src/main/java/com/abel/PersonApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Created by yangyibo on 2018/6/28.\n */\n@SpringBootApplication\npublic class PersonApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(PersonApplication.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/person/src/main/java/com/abel/bean/Person.java",
    "content": "package com.abel.bean;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * Created by yangyibo on 2018/6/28.\n */\n@Entity\npublic class Person {\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String name;\n\n    public Person() {\n        super();\n    }\n\n    public Person(String name) {\n        super();\n        this.name = name;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}\n"
  },
  {
    "path": "springboot-springCloud/person/src/main/java/com/abel/controller/PersonController.java",
    "content": "package com.abel.controller;\nimport com.abel.bean.Person;\nimport com.abel.dao.PersonRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 2018/6/27.\n */\n\n@RestController\npublic class PersonController {\n    @Autowired\n    PersonRepository personRepository;\n\n    @RequestMapping(value = \"/save\", method = RequestMethod.POST)\n    public List<Person> savePerson(@RequestBody String personName) {\n        Person p = new Person(personName);\n        personRepository.save(p);\n        List<Person> people = personRepository.findAll(new PageRequest(0, 10)).getContent();\n        return people;\n    }\n}"
  },
  {
    "path": "springboot-springCloud/person/src/main/java/com/abel/dao/PersonRepository.java",
    "content": "package com.abel.dao;\nimport com.abel.bean.Person;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * Created by yangyibo on 2018/6/28.\n */\npublic interface PersonRepository extends JpaRepository<Person, Long>{\n\n}\n"
  },
  {
    "path": "springboot-springCloud/person/src/main/resources/application.yml",
    "content": "server:\n  port: 8082\n \n\nspring:\n  jpa:\n    hibernate:\n      ddl-auto: update\n\n"
  },
  {
    "path": "springboot-springCloud/person/src/main/resources/bootstrap.yml",
    "content": "spring:\n  application:\n    name: person\n  cloud:\n    config:\n      enabled: true\n      discovery:\n        enabled: true\n        service-id: CONFIG #1\neureka:\n  instance:\n    non-secure-port: ${server.port:8082}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/person/target/classes/application.yml",
    "content": "server:\n  port: 8082\n \n\nspring:\n  jpa:\n    hibernate:\n      ddl-auto: update\n\n"
  },
  {
    "path": "springboot-springCloud/person/target/classes/bootstrap.yml",
    "content": "spring:\n  application:\n    name: person\n  cloud:\n    config:\n      enabled: true\n      discovery:\n        enabled: true\n        service-id: CONFIG #1\neureka:\n  instance:\n    non-secure-port: ${server.port:8082}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.abel</groupId>\n    <artifactId>springCloud</artifactId>\n    <packaging>pom</packaging>\n    <version>1.0-SNAPSHOT</version>\n\n    <modules>\n        <module>config</module>\n        <module>discovery</module>\n        <module>ui</module>\n        <module>person</module>\n        <module>some</module>\n        <module>monitor</module>\n    </modules>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <!-- 替换 spring-boot-starter-parent 为 cloud-->\n    <parent>\n        <groupId>org.springframework.cloud</groupId>\n        <artifactId>spring-cloud-starter-parent</artifactId>\n        <version>Angel.SR3</version>\n        <relativePath/>\n    </parent>\n\n    <!--公共依赖-->\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>com.spotify</groupId>\n                    <artifactId>docker-maven-plugin</artifactId>\n                    <version>0.2.9</version>\n                    <configuration>\n                        <skipDockerBuild>true</skipDockerBuild>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>spring-milestones</id>\n            <name>Spring Milestones</name>\n            <url>https://repo.spring.io/milestone</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n    <pluginRepositories>\n        <pluginRepository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </pluginRepository>\n        <pluginRepository>\n            <id>spring-milestones</id>\n            <name>Spring Milestones</name>\n            <url>https://repo.spring.io/milestone</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n</project>"
  },
  {
    "path": "springboot-springCloud/some/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>some</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-config-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-eureka</artifactId>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-springCloud/some/src/main/java/com/abel/SomeApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created by yangyibo on 2018/6/28.\n */\n@SpringBootApplication\n@EnableDiscoveryClient\n@RestController\npublic class SomeApplication {\n    @Value(\"${my.message}\") //Value 值来自于config server\n    private String message;\n\n    @RequestMapping(value = \"/getsome\")\n    public String getsome(){\n        return message;\n    }\n    public static void main(String[] args) {\n        SpringApplication.run(SomeApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/some/src/main/resources/application.yml",
    "content": "server:\n  port: 8083\n"
  },
  {
    "path": "springboot-springCloud/some/src/main/resources/bootstrap.yml",
    "content": "spring:\n  application:\n    name: some\n  cloud:\n    config:\n      enabled: true\n      discovery:\n        enabled: true\n        service-id: CONFIG\neureka:\n  instance:\n    non-secure-port: ${server.port:8083}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/some/target/classes/application.yml",
    "content": "server:\n  port: 8083\n"
  },
  {
    "path": "springboot-springCloud/some/target/classes/bootstrap.yml",
    "content": "spring:\n  application:\n    name: some\n  cloud:\n    config:\n      enabled: true\n      discovery:\n        enabled: true\n        service-id: CONFIG\neureka:\n  instance:\n    non-secure-port: ${server.port:8083}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/ui/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>springCloud</artifactId>\n        <groupId>com.abel</groupId>\n        <version>1.0-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>ui</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-hystrix</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-zuul</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-config-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-eureka</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-feign</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-ribbon</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>bootstrap</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>angularjs</artifactId>\n            <version>1.3.15</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>angular-ui-router</artifactId>\n            <version>0.2.13</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>jquery</artifactId>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/UiApplication.java",
    "content": "package com.abel;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;\nimport org.springframework.cloud.netflix.eureka.EnableEurekaClient;\nimport org.springframework.cloud.netflix.feign.EnableFeignClients;\nimport org.springframework.cloud.netflix.zuul.EnableZuulProxy;\n\n/**\n * Created by yangyibo on 2018/6/29.\n */\n@SpringBootApplication\n@EnableEurekaClient\n@EnableFeignClients //开启fegin 客户端支持\n@EnableCircuitBreaker //开启CircuitBreaker的支持\n@EnableZuulProxy //开启网关代理支持\npublic class UiApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(UiApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/bean/Person.java",
    "content": "package com.abel.bean;\n\n/**\n * Created by yangyibo on 2018/6/29.\n */\npublic class Person {\n    private Long id;\n\n    private String name;\n\n\n    public Person() {\n        super();\n    }\n\n    public Person(String name) {\n        super();\n        this.name = name;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/controller/UiController.java",
    "content": "package com.abel.controller;\n\nimport com.abel.bean.Person;\nimport com.abel.service.PersonHystrixService;\nimport com.abel.service.SomeHystrixService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 2018/6/29.\n */\n@RestController\npublic class UiController {\n    @Autowired\n    private SomeHystrixService someHystrixService;\n\n    @Autowired\n    private PersonHystrixService personHystrixService;\n\n    @RequestMapping(\"/dispatch\")\n    public List<Person> sendMessage(@RequestBody String personName) {\n        return personHystrixService.save(personName);\n    }\n\n    @RequestMapping(value = \"/getsome\",produces={MediaType.TEXT_PLAIN_VALUE})\n    public String getSome(){\n        return someHystrixService.getSome();\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/service/PersonHystrixService.java",
    "content": "package com.abel.service;\n\nimport com.abel.bean.Person;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n/**\n * Created by yangyibo on 2018/6/29.\n * 调用person service的断路器\n */\n@Service\npublic class PersonHystrixService {\n\n    @Autowired\n    PersonService personService;\n\n    @HystrixCommand(fallbackMethod = \"fallbackSave\") //使用HystrixCommand的fallbackMethod参数指定，调用失败的时候调用后备方法 fallbackMethod\n    public List<Person> save(String name) {\n        return personService.save(name);\n    }\n\n    public List<Person> fallbackSave(String name){\n        List<Person> list = new ArrayList<Person>();\n        Person p = new Person(name+\"没有保存成功，Person Service 故障\");\n        list.add(p);\n        return list;\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/service/PersonService.java",
    "content": "package com.abel.service;\n\nimport com.abel.bean.Person;\nimport org.springframework.cloud.netflix.feign.FeignClient;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 2018/6/29.\n * 使用 Feign 调用person service\n * 我们只需要通过简单在接口中声明方法即可调用Person的 Rest服务\n */\n@FeignClient(\"person\")\npublic interface PersonService {\n    @RequestMapping(method = RequestMethod.POST, value = \"/save\",\n            produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)\n    @ResponseBody\n    List<Person> save(@RequestBody String  name);\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/java/com/abel/service/SomeHystrixService.java",
    "content": "package com.abel.service;\n\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Created by yangyibo on 2018/6/29.\n * 使用ribbon 调用some service 并使用断路器\n */\n@Service\npublic class SomeHystrixService {\n\n    @Autowired\n    RestTemplate restTemplate; // springboot 下使用ribbon ，只需注入一个 RestTemplate，springboot 已经为我们做好了配置\n\n    @HystrixCommand(fallbackMethod = \"fallbackSome\") //HystrixCommand 的参数指定，当调用失败时，使用备用方法fallbackMethod\n    public String getSome() {\n        return restTemplate.getForObject(\"http://some/getsome\", String.class);\n    }\n\n    public String fallbackSome(){\n        return \"some service模块故障\";\n    }\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/application.yml",
    "content": "server:\n  port: 80\n  \n\n  \n\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/bootstrap.yml",
    "content": "spring:\n  application:\n    name: ui\n\neureka:\n  instance:\n    non-secure-port: ${server.port:80}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/static/css/application.css",
    "content": "body {\n\tpadding-top: 60px;\n}\n\nh1, h2, h3, h4, h5, h6 {\n    font-family: microsoft yahei;\n}\np, div {\n    font-family: microsoft yahei;\n    font-size: 12px;\n}\n\n.longtext {\n    word-break:break-all;\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n \t<meta charset=\"utf-8\" />\n    <title>原生云应用</title>\n    <link rel=\"stylesheet\" href=\"/webjars/bootstrap/3.2.0/css/bootstrap.css\" />\n    <link rel=\"stylesheet\" href=\"/css/application.css\"/>\n    <script src=\"/webjars/jquery/2.1.1/jquery.js\" > </script>\n    <script src=\"/webjars/bootstrap/3.2.0/js/bootstrap.js\"> </script>\n    <script src=\"/webjars/angularjs/1.3.15/angular.js\"> </script>\n    <script src=\"/webjars/angularjs/1.3.15/angular-resource.js\"> </script>\n    <script src=\"/webjars/angular-ui-router/0.2.13/angular-ui-router.js\"> </script>\n    <script  src=\"/js/app.js\"> </script>\n</head>\n<body>\n<div class=\"navbar navbar-default navbar-fixed-top\" role=\"navigation\">\n    <div class=\"container-fluid\">\n        <div class=\"navbar-header\">\n            <a class=\"navbar-brand\" href=\"#person\">原生云应用</a>\n            \n        </div>\n        <div class=\"navbar-collapse collapse\">\n            <ul class=\"nav navbar-nav navbar-right\">\n                <li><a href=\"#person\">Person服务</a></li>\n                <li><a href=\"#some\">Some服务</a></li>\n            </ul>\n        </div>\n    </div>\n</div>\n<div class=\"container-fluid\">\n    <div ng-app=\"uiApp\">\n        <div ui-view=\"\"></div>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/static/js/app.js",
    "content": "var uiApp = angular.module(\"uiApp\", [\"ui.router\"]);\n\nuiApp.config(function ($stateProvider, $urlRouterProvider) {\n    $urlRouterProvider.otherwise(\"person\");\n\n    $stateProvider\n        .state('person', {\n            url: '/person',\n            templateUrl: '/tpl/person.html',\n            controller: 'PersonController'\n        })\n        .state('some',{\n        \turl:'/some',\n        \t templateUrl: '/tpl/some.html',\n             controller: 'SomeController'\n        });\n});\n\n\nuiApp.controller(\"PersonController\", function ($scope, $http) {\n\n        $scope.people = \"\";\n        $scope.errorMessage = \"\";\n\n    $scope.getMessageResponse = function(personName) {\n    \t$http.post('/dispatch', personName).success(function(data){\n            $scope.people = data;\n            $scope.errorMessage = \"\";\n        }).error(function() {\n            $scope.errorMessage = \"错误\";\n        });\n    }\n  \n});\n\n\nuiApp.controller(\"SomeController\", function ($scope, $http) {\n\t$scope.str = \"\";\n    $scope.errorMessage = \"\";\n\n$scope.getSome = function(){\n\t$http.get('/getsome').success(function(data){\n        $scope.str = data;\n        $scope.errorMessage = \"\";\n    }).error(function() {\n        $scope.errorMessage = \"错误\";\n    });\n}\n});"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/static/tpl/person.html",
    "content": " <div class=\"row\">\n    <div class=\"col-xs-12\">\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <h3>通过Person Service保存person</h3>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <div class=\"row\" ng-if=\"errorMessage != ''\">\n                    <div class=\"col-xs-12\">\n                        <p class=\"bg-danger text-center\">\n                            <span ng-bind=\"errorMessage\"></span>\n                        </p>\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-xs-12\">\n                <form>\n                    <div class=\"form-group\">\n                        <input type=\"text\" class=\"form-control\" id=\"personName\" ng-model=\"personName\" placeholder=\"填写名字\">\n                    </div>\n                    <div class=\"form-group\" ng-if=\"people != ''\">\n                        <div ng-repeat=\"person in people\">\n                        \t<label>id:{{person.id}},name:{{person.name}}</label>\n                        </div>\n                    </div>\n                    <button type=\"submit\" class=\"btn btn-default\" ng-click=\"getMessageResponse(personName)\">保存</button>\n                </form>\n            </div>\n           \n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "springboot-springCloud/ui/src/main/resources/static/tpl/some.html",
    "content": " <div class=\"row\">\n    <div class=\"col-xs-12\">\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <h3>从 Some Service获得字符</h3>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <div class=\"row\" ng-if=\"errorMessage != ''\">\n                    <div class=\"col-xs-12\">\n                        <p class=\"bg-danger text-center\">\n                            <span ng-bind=\"errorMessage\"></span>\n                        </p>\n                    </div>\n                </div>\n            </div>\n        \n            <div class=\"col-xs-12\">\n            \t<button type=\"button\" class=\"btn btn-default\" ng-click=\"getSome()\">获取</button>\n            \t<div>\n                 \t<label>{{str}}</label>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/application.yml",
    "content": "server:\n  port: 80\n  \n\n  \n\n"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/bootstrap.yml",
    "content": "spring:\n  application:\n    name: ui\n\neureka:\n  instance:\n    non-secure-port: ${server.port:80}\n  client:\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/static/css/application.css",
    "content": "body {\n\tpadding-top: 60px;\n}\n\nh1, h2, h3, h4, h5, h6 {\n    font-family: microsoft yahei;\n}\np, div {\n    font-family: microsoft yahei;\n    font-size: 12px;\n}\n\n.longtext {\n    word-break:break-all;\n}\n"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n \t<meta charset=\"utf-8\" />\n    <title>原生云应用</title>\n    <link rel=\"stylesheet\" href=\"/webjars/bootstrap/3.2.0/css/bootstrap.css\" />\n    <link rel=\"stylesheet\" href=\"/css/application.css\"/>\n    <script src=\"/webjars/jquery/2.1.1/jquery.js\" > </script>\n    <script src=\"/webjars/bootstrap/3.2.0/js/bootstrap.js\"> </script>\n    <script src=\"/webjars/angularjs/1.3.15/angular.js\"> </script>\n    <script src=\"/webjars/angularjs/1.3.15/angular-resource.js\"> </script>\n    <script src=\"/webjars/angular-ui-router/0.2.13/angular-ui-router.js\"> </script>\n    <script  src=\"/js/app.js\"> </script>\n</head>\n<body>\n<div class=\"navbar navbar-default navbar-fixed-top\" role=\"navigation\">\n    <div class=\"container-fluid\">\n        <div class=\"navbar-header\">\n            <a class=\"navbar-brand\" href=\"#person\">原生云应用</a>\n            \n        </div>\n        <div class=\"navbar-collapse collapse\">\n            <ul class=\"nav navbar-nav navbar-right\">\n                <li><a href=\"#person\">Person服务</a></li>\n                <li><a href=\"#some\">Some服务</a></li>\n            </ul>\n        </div>\n    </div>\n</div>\n<div class=\"container-fluid\">\n    <div ng-app=\"uiApp\">\n        <div ui-view=\"\"></div>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/static/js/app.js",
    "content": "var uiApp = angular.module(\"uiApp\", [\"ui.router\"]);\n\nuiApp.config(function ($stateProvider, $urlRouterProvider) {\n    $urlRouterProvider.otherwise(\"person\");\n\n    $stateProvider\n        .state('person', {\n            url: '/person',\n            templateUrl: '/tpl/person.html',\n            controller: 'PersonController'\n        })\n        .state('some',{\n        \turl:'/some',\n        \t templateUrl: '/tpl/some.html',\n             controller: 'SomeController'\n        });\n});\n\n\nuiApp.controller(\"PersonController\", function ($scope, $http) {\n\n        $scope.people = \"\";\n        $scope.errorMessage = \"\";\n\n    $scope.getMessageResponse = function(personName) {\n    \t$http.post('/dispatch', personName).success(function(data){\n            $scope.people = data;\n            $scope.errorMessage = \"\";\n        }).error(function() {\n            $scope.errorMessage = \"错误\";\n        });\n    }\n  \n});\n\n\nuiApp.controller(\"SomeController\", function ($scope, $http) {\n\t$scope.str = \"\";\n    $scope.errorMessage = \"\";\n\n$scope.getSome = function(){\n\t$http.get('/getsome').success(function(data){\n        $scope.str = data;\n        $scope.errorMessage = \"\";\n    }).error(function() {\n        $scope.errorMessage = \"错误\";\n    });\n}\n});"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/static/tpl/person.html",
    "content": " <div class=\"row\">\n    <div class=\"col-xs-12\">\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <h3>通过Person Service保存person</h3>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <div class=\"row\" ng-if=\"errorMessage != ''\">\n                    <div class=\"col-xs-12\">\n                        <p class=\"bg-danger text-center\">\n                            <span ng-bind=\"errorMessage\"></span>\n                        </p>\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-xs-12\">\n                <form>\n                    <div class=\"form-group\">\n                        <input type=\"text\" class=\"form-control\" id=\"personName\" ng-model=\"personName\" placeholder=\"填写名字\">\n                    </div>\n                    <div class=\"form-group\" ng-if=\"people != ''\">\n                        <div ng-repeat=\"person in people\">\n                        \t<label>id:{{person.id}},name:{{person.name}}</label>\n                        </div>\n                    </div>\n                    <button type=\"submit\" class=\"btn btn-default\" ng-click=\"getMessageResponse(personName)\">保存</button>\n                </form>\n            </div>\n           \n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "springboot-springCloud/ui/target/classes/static/tpl/some.html",
    "content": " <div class=\"row\">\n    <div class=\"col-xs-12\">\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <h3>从 Some Service获得字符</h3>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-xs-12\">\n                <div class=\"row\" ng-if=\"errorMessage != ''\">\n                    <div class=\"col-xs-12\">\n                        <p class=\"bg-danger text-center\">\n                            <span ng-bind=\"errorMessage\"></span>\n                        </p>\n                    </div>\n                </div>\n            </div>\n        \n            <div class=\"col-xs-12\">\n            \t<button type=\"button\" class=\"btn btn-default\" ng-click=\"getSome()\">获取</button>\n            \t<div>\n                 \t<label>{{str}}</label>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "springboot-springSecurity2/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-security2</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/config/DBconfig.java",
    "content": "package com.us.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\npublic class DBconfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/config/MyBatisConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class MyBatisConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"sqlSessionFactory\")\n    public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {\n        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        // sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n        sessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n        return sessionFactory;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/config/MyBatisScannerConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/config/TransactionConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/config/WebSecurityConfig.java",
    "content": "package com.us.example.config;\n\nimport com.us.example.security.CustomUserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\n@EnableWebSecurity\n@EnableGlobalMethodSecurity(securedEnabled = true)\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n     private  CustomUserService customUserService;\n\n\n    @Autowired\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserService).passwordEncoder(new BCryptPasswordEncoder());\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n                .csrf().disable()\n                .authorizeRequests()\n                .antMatchers(\"/users/**\")\n                .authenticated()\n                .antMatchers(HttpMethod.POST)\n                .authenticated()\n                .antMatchers(HttpMethod.PUT)\n                .authenticated()\n                .antMatchers(HttpMethod.DELETE)\n                .authenticated()\n                .antMatchers(\"/**\")\n                .permitAll()\n                .and()\n                .sessionManagement()\n                .and()\n                .httpBasic();\n    }\n\n\n\n}\n\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/controller/HomeController.java",
    "content": "package com.us.example.controller;\n\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.SysUser;\nimport com.us.example.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.annotation.Secured;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Controller\n@RequestMapping(\"/users\")\npublic class HomeController {\n    @Autowired\n    UserService userService;\n\n    @RequestMapping(method = RequestMethod.GET)\n    @ResponseBody\n    public String getUsers() {\n        return \"getUsers\";\n    }\n\n    @Secured({\"ROLE_ADMIN\",\"ROLE_USER\"})\n    @RequestMapping(method = RequestMethod.POST)\n    @ResponseBody\n    public Object save(@RequestBody SysUser user) {\n        return  userService.create(user);\n    }\n\n\n    @Secured(\"ROLE_ADMIN\")\n    @RequestMapping(method = RequestMethod.PUT)\n    @ResponseBody\n    public String update() {\n        return \"updateUser\";\n    }\n\n\n    @Secured(\"ROLE_ADMIN\")\n    @RequestMapping(method = RequestMethod.DELETE)\n    @ResponseBody\n    public String delete() {\n        return \"deleteUser\";\n    }\n\n\n}\n\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/controller/LoginController.java",
    "content": "package com.us.example.controller;\n\nimport com.us.example.domain.SysUser;\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n\n/**\n * Created by yangyibo on 17/3/1.\n */\n@RestController\npublic class LoginController {\n\n    @RequestMapping(value = \"/login\")\n    @ResponseBody\n    //用户名密码是用base64 加密 原文为 admin:admin 即 用户名:密码  内容是放在request.getHeader 的 \"authorization\" 中\n    public Object login(@AuthenticationPrincipal SysUser loginedUser, @RequestParam(name = \"logout\", required = false) String logout) {\n        if (logout != null) {\n            return null;\n        }\n        if (loginedUser != null) {\n            return loginedUser;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/dao/UserDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.SysUser;\n\n\npublic interface UserDao {\n     SysUser findByUserName(String username);\n\n     int create (SysUser sysUser);\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/domain/SysRole.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysRole {\n\n    private Integer id;\n    private String name;\n    public Integer getId() {\n        return id;\n    }\n    public void setId(Integer id) {\n        this.id = id;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/domain/SysUser.java",
    "content": "package com.us.example.domain;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysUser implements UserDetails {  // implements UserDetails 用于登录时 @AuthenticationPrincipal 标签取值\n    private Integer id;\n    private String username;\n    @JsonIgnore\n    private String password;\n    private String rawPassword;\n    @JsonIgnore\n    private List<SysRole> roles;\n    private List<? extends GrantedAuthority> authorities;\n\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public List<SysRole> getRoles() {\n        return roles;\n    }\n\n    public void setRoles(List<SysRole> roles) {\n        this.roles = roles;\n    }\n\n    public String getRawPassword() {\n        return rawPassword;\n    }\n\n    public void setRawPassword(String rawPassword) {\n        this.rawPassword = rawPassword;\n    }\n\n\n    @JsonIgnore\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @JsonIgnore\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @JsonIgnore\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n\n    @JsonIgnore\n    @Override\n    public boolean isEnabled() {\n        return true;\n    }\n\n    @JsonIgnore\n    @Override\n    public Collection<? extends GrantedAuthority> getAuthorities() {\n        return authorities;\n    }\n\n    public void setGrantedAuthorities(List<? extends GrantedAuthority> authorities) {\n        this.authorities = authorities;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/security/CustomUserService.java",
    "content": "package com.us.example.security;\n\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.SysRole;\nimport com.us.example.domain.SysUser;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Service\npublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口\n\n    @Autowired\n    UserDao userDao;\n    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CustomUserService.class);\n\n    @Override\n    public UserDetails loadUserByUsername(String username) { //重写loadUserByUsername 方法获得 userdetails 类型用户\n\n        SysUser user = userDao.findByUserName(username);\n        if(user == null){\n            throw new UsernameNotFoundException(\"用户名不存在\");\n        }\n        List<SimpleGrantedAuthority> authorities = new ArrayList<>();\n        //用于添加用户的权限。只要把用户权限添加到authorities 就万事大吉。\n        for(SysRole role:user.getRoles())\n        {\n            authorities.add(new SimpleGrantedAuthority(role.getName()));\n            logger.info(\"loadUserByUsername: \" + user);\n        }\n        user.setGrantedAuthorities(authorities); //用于登录时 @AuthenticationPrincipal 标签取值\n        return user;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/service/UserService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.SysUser;\nimport com.us.example.util.MD5Util;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created by yangyibo on 17/3/2.\n */\n@Service\npublic class UserService {\n    @Autowired\n    UserDao userDao;\n\n    public SysUser create(SysUser sysUser){\n        //进行加密\n        BCryptPasswordEncoder encoder =new BCryptPasswordEncoder();\n        sysUser.setPassword(encoder.encode(MD5Util.encode(sysUser.getRawPassword().trim())));\n        userDao.create(sysUser);\n    return sysUser;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/util/BCryptPasswordEncoderTest.java",
    "content": "package com.us.example.util;\n\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\n\n/**\n * Created by yangyibo on 17/3/2.\n */\npublic class BCryptPasswordEncoderTest {\n    public static void main(String[] args) {\n\n        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n        System.out.println(\"encoder:  \" + encoder.encode(\"abel\"));\n        System.out.println(\"encoder:  \" + encoder.encode(\"admin\"));\n\n        if (encoder.matches(\"abel\", \"$2a$10$IAz6WzJ314LH1NXq7Rf.dOYPP2uvzk08g.eAl9l4DRG4YsxavEV4W\")) {\n            System.out.println(\"encoder: true\");\n        }\n\n\n        System.out.println(\"------------华丽的分割线-----------------------\");\n        String Md5Password = MD5Util.encode(\"abel\");\n        System.out.println(\"Md5Password:  \" + Md5Password);\n        System.out.println(\"encoder:  \" + encoder.encode(Md5Password));\n        if (encoder.matches(Md5Password, \"$2a$10$37MXEfzlbtC6QSsRTlRhIOmykMRJtO5mU8Y.yiJBjy1x4WYWFR5gG\")) {\n            System.out.println(\"Md5Password: true\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/java/com/us/example/util/MD5Util.java",
    "content": "package com.us.example.util;\n\nimport java.security.MessageDigest;\n\n/**\n * Created by yangyibo on 9/8/17.\n */\npublic class MD5Util {\n    private static final String SALT = \"salt\";\n\n    public static String encode(String password) {\n        password = password + SALT;\n        return processEncode(password);\n    }\n\n    public static String processEncode(String password) {\n        MessageDigest md5 = null;\n        try {\n            md5 = MessageDigest.getInstance(\"MD5\");\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n        char[] charArray = password.toCharArray();\n        byte[] byteArray = new byte[charArray.length];\n\n        for (int i = 0; i < charArray.length; i++)\n            byteArray[i] = (byte) charArray[i];\n        byte[] md5Bytes = md5.digest(byteArray);\n        StringBuffer hexValue = new StringBuffer();\n        for (int i = 0; i < md5Bytes.length; i++) {\n            int val = ((int) md5Bytes[i]) & 0xff;\n            if (val < 16) {\n                hexValue.append(\"0\");\n            }\n\n            hexValue.append(Integer.toHexString(val));\n        }\n        return hexValue.toString();\n    }\n\n    public static void main(String[] args) {\n        System.out.println(MD5Util.encode(\"abel\"));\n        System.out.println(MD5Util.encode(\"admin\"));\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?characterEncoding=utf-8&useSSL=false\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\nserver.port=8099\r\n\r\nlogging.level.org.springframework.security= INFO\r\nspring.thymeleaf.cache=false\r\n"
  },
  {
    "path": "springboot-springSecurity2/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.us.example.domain.SysUser\">\n        <id property=\"id\" column=\"ID\"/>\n        <result property=\"username\" column=\"username\"/>\n        <result property=\"password\" column=\"PASSWORD\"/>\n        <collection property=\"roles\" ofType=\"com.us.example.domain.SysRole\">\n            <result column=\"name\" property=\"name\"/>\n        </collection>\n\n    </resultMap>\n    <select id=\"findByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        where username= #{username}\n\t</select>\n\n    <insert id=\"create\" parameterType=\"com.us.example.domain.SysUser\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n            SELECT LAST_INSERT_ID()\n        </selectKey>\n       INSERT into Sys_User\n       (username,password)\n       values\n       (#{username},#{password})\n    </insert>\n</mapper>"
  },
  {
    "path": "springboot-springSecurity3/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.us</groupId>\n    <artifactId>springboot-security3</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.2.7</mybatis.version>\n        <mybatis-spring.version>1.2.2</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.thymeleaf.extras</groupId>\n            <artifactId>thymeleaf-extras-springsecurity4</artifactId>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/Application.java",
    "content": "package com.us.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.us.example\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/DBconfig.java",
    "content": "package com.us.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\npublic class DBconfig {\n    @Autowired\n    private Environment env;\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/MyBatisConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class MyBatisConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"sqlSessionFactory\")\n    public SqlSessionFactoryBean sqlSessionFactory(ApplicationContext applicationContext) throws Exception {\n        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        // sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n        sessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n        return sessionFactory;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/MyBatisScannerConfig.java",
    "content": "package com.us.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/TransactionConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/WebMvcConfig.java",
    "content": "package com.us.example.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Configuration\n\npublic class WebMvcConfig extends WebMvcConfigurerAdapter{\n\n    @Override\n    public void addViewControllers(ViewControllerRegistry registry) {\n        registry.addViewController(\"/login\").setViewName(\"login\");\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/config/WebSecurityConfig.java",
    "content": "package com.us.example.config;\n\nimport com.us.example.service.CustomUserService;\nimport com.us.example.service.MyFilterSecurityInterceptor;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.web.access.intercept.FilterSecurityInterceptor;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n\n\n@Configuration\n@EnableWebSecurity\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;\n\n\n    @Bean\n    UserDetailsService customUserService() { //注册UserDetailsService 的bean\n        return new CustomUserService();\n    }\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserService()); //user Details Service验证\n\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.authorizeRequests()\n                .anyRequest().authenticated() //任何请求,登录后可以访问\n                .and()\n                .formLogin()\n                .loginPage(\"/login\")\n                .failureUrl(\"/login?error\")\n                .permitAll() //登录页面用户任意访问\n                .and()\n                .logout().permitAll(); //注销行为任意访问\n        http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)\n                .csrf().disable();\n\n\n    }\n}\n\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/controller/HomeController.java",
    "content": "package com.us.example.controller;\n\nimport com.us.example.domain.Msg;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Controller\npublic class HomeController {\n\n    @RequestMapping(\"/\")\n    public String index(Model model){\n        Msg msg =  new Msg(\"测试标题\",\"测试内容\",\"欢迎来到HOME页面,您拥有 ROLE_HOME 权限\");\n        model.addAttribute(\"msg\", msg);\n        return \"home\";\n    }\n\n\n    @RequestMapping(\"/admin\")\n    @ResponseBody\n    public String hello(){\n        return \"hello admin\";\n    }\n\n    @RequestMapping(\"/login\")\n    public String login(){\n        return \"login\";\n    }\n\n    @RequestMapping(value = \"/user\", method = RequestMethod.GET)\n    @ResponseBody\n    public String getList(){\n        return \"hello getList\";\n    }\n\n\n    @RequestMapping(value = \"/user\", method = RequestMethod.POST)\n    @ResponseBody\n    public String save(){\n        return \"hello save\";\n    }\n\n\n    @RequestMapping(value = \"/user\", method = RequestMethod.PUT)\n    @ResponseBody\n    public String update(){\n        return \"hello update\";\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/dao/PermissionDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.Permission;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/20.\n */\npublic interface PermissionDao {\n    public List<Permission> findAll();\n    public List<Permission> findByAdminUserId(int userId);\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/dao/UserDao.java",
    "content": "package com.us.example.dao;\n\nimport com.us.example.domain.SysUser;\n\n\npublic interface UserDao {\n    public SysUser findByUserName(String username);\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/domain/Msg.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n    public class Msg {\n        private String title;\n        private String content;\n        private String etraInfo;\n\n        public Msg(String title, String content, String etraInfo) {\n            super();\n            this.title = title;\n            this.content = content;\n            this.etraInfo = etraInfo;\n        }\n        public String getTitle() {\n            return title;\n        }\n        public void setTitle(String title) {\n            this.title = title;\n        }\n        public String getContent() {\n            return content;\n        }\n        public void setContent(String content) {\n            this.content = content;\n        }\n        public String getEtraInfo() {\n            return etraInfo;\n        }\n        public void setEtraInfo(String etraInfo) {\n            this.etraInfo = etraInfo;\n        }\n\n    }\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/domain/Permission.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/20.\n */\npublic class Permission {\n\n    private int id;\n    //权限名称\n    private String name;\n\n    //权限描述\n    private String descritpion;\n\n    //授权链接\n    private String url;\n\n    //父节点id\n    private int pid;\n\n    //请求方法\n    private String method;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDescritpion() {\n        return descritpion;\n    }\n\n    public void setDescritpion(String descritpion) {\n        this.descritpion = descritpion;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public int getPid() {\n        return pid;\n    }\n\n    public void setPid(int pid) {\n        this.pid = pid;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/domain/SysRole.java",
    "content": "package com.us.example.domain;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysRole {\n\n    private Integer id;\n    private String name;\n    public Integer getId() {\n        return id;\n    }\n    public void setId(Integer id) {\n        this.id = id;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/domain/SysUser.java",
    "content": "package com.us.example.domain;\n\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\npublic class SysUser {\n    private Integer id;\n    private String username;\n    private String password;\n\n    private List<SysRole> roles;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public List<SysRole> getRoles() {\n        return roles;\n    }\n\n    public void setRoles(List<SysRole> roles) {\n        this.roles = roles;\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/service/CustomUserService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.dao.PermissionDao;\nimport com.us.example.dao.UserDao;\nimport com.us.example.domain.Permission;\nimport com.us.example.domain.SysRole;\nimport com.us.example.domain.SysUser;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/1/18.\n */\n@Service\npublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口\n\n    @Autowired\n    UserDao userDao;\n    @Autowired\n    PermissionDao permissionDao;\n\n    public UserDetails loadUserByUsername(String username) {\n        SysUser user = userDao.findByUserName(username);\n        if (user != null) {\n            List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());\n            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();\n            for (Permission permission : permissions) {\n                if (permission != null && permission.getName() != null) {\n\n                    GrantedAuthority grantedAuthority = new MyGrantedAuthority(permission.getUrl(), permission.getMethod());\n                    grantedAuthorities.add(grantedAuthority);\n                }\n            }\n            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);\n        } else {\n            throw new UsernameNotFoundException(\"admin: \" + username + \" do not exist!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/service/MyAccessDecisionManager.java",
    "content": "package com.us.example.service;\n\nimport org.springframework.security.access.AccessDecisionManager;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.authentication.InsufficientAuthenticationException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Collection;\nimport java.util.Iterator;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyAccessDecisionManager implements AccessDecisionManager {\n\n    //decide 方法是判定是否拥有权限的决策方法\n    @Override\n    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {\n\n        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();\n        String url, method;\n        AntPathRequestMatcher matcher;\n        for (GrantedAuthority ga : authentication.getAuthorities()) {\n            if (ga instanceof MyGrantedAuthority) {\n                MyGrantedAuthority urlGrantedAuthority = (MyGrantedAuthority) ga;\n                url = urlGrantedAuthority.getPermissionUrl();\n                method = urlGrantedAuthority.getMethod();\n                matcher = new AntPathRequestMatcher(url);\n                if (matcher.matches(request)) {\n                    //当权限表权限的method为ALL时表示拥有此路径的所有请求方式权利。\n                    if (method.equals(request.getMethod()) || \"ALL\".equals(method)) {\n                        return;\n                    }\n                }\n            } else if (ga.getAuthority().equals(\"ROLE_ANONYMOUS\")) {//未登录只允许访问 login 页面\n                matcher = new AntPathRequestMatcher(\"/login\");\n                if (matcher.matches(request)) {\n                    return;\n                }\n            }\n        }\n        throw new AccessDeniedException(\"no right\");\n    }\n\n\n\n    @Override\n    public boolean supports(ConfigAttribute attribute) {\n        return true;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/service/MyFilterSecurityInterceptor.java",
    "content": "package com.us.example.service;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.SecurityMetadataSource;\nimport org.springframework.security.access.intercept.AbstractSecurityInterceptor;\nimport org.springframework.security.access.intercept.InterceptorStatusToken;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.stereotype.Service;\n\nimport java.io.IOException;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {\n\n\n    @Autowired\n    private FilterInvocationSecurityMetadataSource securityMetadataSource;\n\n    @Autowired\n    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {\n        super.setAccessDecisionManager(myAccessDecisionManager);\n    }\n\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\n        FilterInvocation fi = new FilterInvocation(request, response, chain);\n        invoke(fi);\n    }\n\n\n    public void invoke(FilterInvocation fi) throws IOException, ServletException {\n//fi里面有一个被拦截的url\n//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限\n//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够\n        InterceptorStatusToken token = super.beforeInvocation(fi);\n        try {\n//执行下一个拦截器\n            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());\n        } finally {\n            super.afterInvocation(token, null);\n        }\n    }\n\n\n    @Override\n    public void destroy() {\n\n    }\n\n    @Override\n    public Class<?> getSecureObjectClass() {\n        return FilterInvocation.class;\n\n    }\n\n    @Override\n    public SecurityMetadataSource obtainSecurityMetadataSource() {\n        return this.securityMetadataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/service/MyGrantedAuthority.java",
    "content": "package com.us.example.service;\n\nimport org.springframework.security.core.GrantedAuthority;\n\n/**\n * Created by yangyibo on 17/2/15.\n */\npublic class MyGrantedAuthority implements GrantedAuthority {\n\n    private String url;\n    private String method;\n\n    public String getPermissionUrl() {\n        return url;\n    }\n\n    public void setPermissionUrl(String permissionUrl) {\n        this.url = permissionUrl;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public MyGrantedAuthority(String url, String method) {\n        this.url = url;\n        this.method = method;\n    }\n\n    @Override\n    public String getAuthority() {\n        return this.url + \";\" + this.method;\n    }\n}"
  },
  {
    "path": "springboot-springSecurity3/src/main/java/com/us/example/service/MyInvocationSecurityMetadataSourceService.java",
    "content": "package com.us.example.service;\n\nimport com.us.example.dao.PermissionDao;\nimport com.us.example.domain.Permission;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.access.SecurityConfig;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.*;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class MyInvocationSecurityMetadataSourceService  implements\n        FilterInvocationSecurityMetadataSource {\n\n    //此方法是为了判定用户请求的url 是否在权限表中，如果在权限表中，则返回给 decide 方法，用来判定用户是否有此权限。如果不在权限表中则放行。\n    //因为我不想每一次来了请求，都先要匹配一下权限表中的信息是不是包含此url，\n    // 我准备直接拦截，不管请求的url 是什么都直接拦截，然后在MyAccessDecisionManager的decide 方法中做拦截还是放行的决策。\n    //所以此方法的返回值不能返回 null 此处我就随便返回一下。\n    @Override\n    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {\n        Collection<ConfigAttribute> co=new ArrayList<>();\n        co.add(new SecurityConfig(\"null\"));\n        return co;\n    }\n\n    @Override\n    public Collection<ConfigAttribute> getAllConfigAttributes() {\n        return null;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/resources/application.properties",
    "content": "ms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/cache?characterEncoding=utf-8&useSSL=false\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500\r\n\r\n\r\nlogging.level.org.springframework.security= INFO\r\nspring.thymeleaf.cache=false\r\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/resources/mapper/PermissionDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.PermissionDao\">\n<select id=\"findAll\"  resultType=\"com.us.example.domain.Permission\">\n\n   SELECT * from Sys_permission ;\n</select>\n\n <select id=\"findByAdminUserId\" parameterType=\"int\" resultType=\"com.us.example.domain.Permission\">\n      select p.*\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        LEFT JOIN Sys_permission_role spr on spr.role_id=r.id\n        LEFT JOIN Sys_permission p on p.id =spr.permission_id\n        where u.id=#{userId}\n </select>\n </mapper>"
  },
  {
    "path": "springboot-springSecurity3/src/main/resources/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.us.example.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.us.example.domain.SysUser\">\n        <id property=\"id\" column=\"ID\"/>\n        <result property=\"username\" column=\"username\"/>\n        <result property=\"password\" column=\"PASSWORD\"/>\n        <collection property=\"roles\" ofType=\"com.us.example.domain.SysRole\">\n            <result column=\"name\" property=\"name\"/>\n        </collection>\n\n    </resultMap>\n    <select id=\"findByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.*\n\t\t,r.name\n\t\tfrom Sys_User u\n        LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id\n        LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id\n        where username= #{username}\n\t</select>\n</mapper>"
  },
  {
    "path": "springboot-springSecurity3/src/main/resources/templates/home.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\" \n\t  xmlns:sec=\"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title sec:authentication=\"name\"></title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\" />\n<style type=\"text/css\">\nbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n              <li><a th:href=\"@{/admin}\"> admin </a></li>\n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n    \n    \n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n      \t<h1 th:text=\"${msg.title}\"></h1>\n\t\t\n\t\t<p class=\"bg-primary\" th:text=\"${msg.content}\"></p>\n\t\t\n\t\t<div sec:authorize=\"hasRole('ROLE_HOME')\"> <!-- 用户类型为ROLE_ADMIN 显示 -->\n\t\t \t<p class=\"bg-info\" th:text=\"${msg.etraInfo}\"></p>\n\t\t</div>\n          <div sec:authorize=\"hasRole('ROLE_ADMIN')\"> <!-- 用户类型为ROLE_ADMIN 显示 -->\n              <p class=\"bg-info\">恭喜您,您有 ROLE_ADMIN 权限 </p>\n          </div>\n\n          <form th:action=\"@{/logout}\" method=\"post\">\n            <input type=\"submit\" class=\"btn btn-primary\" value=\"注销\"/>\n        </form>\n      </div>\n\n    </div>\n    \n\t\n</body>\n</html>\n"
  },
  {
    "path": "springboot-springSecurity3/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n<meta content=\"text/html;charset=UTF-8\"/>\n<title>登录页面</title>\n<link rel=\"stylesheet\" th:href=\"@{css/bootstrap.min.css}\"/>\n<style type=\"text/css\">\n\tbody {\n  padding-top: 50px;\n}\n.starter-template {\n  padding: 40px 15px;\n  text-align: center;\n}\n</style>\n</head>\n<body>\n\t\n\t <nav class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <a class=\"navbar-brand\" href=\"#\">Spring Security演示</a>\n        </div>\n        <div id=\"navbar\" class=\"collapse navbar-collapse\">\n          <ul class=\"nav navbar-nav\">\n           <li><a th:href=\"@{/}\"> 首页 </a></li>\n           \n          </ul>\n        </div><!--/.nav-collapse -->\n      </div>\n    </nav>\n     <div class=\"container\">\n\n      <div class=\"starter-template\">\n       <p th:if=\"${param.logout}\" class=\"bg-warning\">已成功注销</p><!-- 1 -->\n\t\t\t<p th:if=\"${param.error}\" class=\"bg-danger\">有错误，请重试</p> <!-- 2 -->\n\t\t\t<h2>使用账号密码登录</h2>\n\t\t\t<form name=\"form\" th:action=\"@{/login}\" action=\"/login\" method=\"POST\"> <!-- 3 -->\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"username\">账号</label>\n\t\t\t\t\t<input type=\"text\" class=\"form-control\" name=\"username\" value=\"\" placeholder=\"账号\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"password\">密码</label>\n\t\t\t\t\t<input type=\"password\" class=\"form-control\" name=\"password\" placeholder=\"密码\" />\n\t\t\t\t</div>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n      </div>\n\n    </div>\n\t\t\n</body>\n</html>"
  },
  {
    "path": "springboot-springSecurity4/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.example</groupId>\n    <artifactId>springboot-springSecurity4</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.us.Application</start-class>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <mybatis.version>3.4.0</mybatis.version>\n        <mybatis-spring.version>1.3.0</mybatis-spring.version>\n    </properties>\n\n    <dependencies>\n        <!--springboot-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.thymeleaf.extras</groupId>\n            <artifactId>thymeleaf-extras-springsecurity4</artifactId>\n        </dependency>\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n        </dependency>\n\n        <!--mybatis-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>${mybatis.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>${mybatis-spring.version}</version>\n        </dependency>\n\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/Application.java",
    "content": "package com.yy.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.yy.example\")\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/bean/Permission.java",
    "content": "package com.yy.example.bean;\n\n\npublic class Permission {\n    private Integer id;\n    private String name;\n    private String permissionUrl;\n    private String method;\n    private String description;\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPermissionUrl() {\n        return permissionUrl;\n    }\n\n    public void setPermissionUrl(String permissionUrl) {\n        this.permissionUrl = permissionUrl;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"Permission{\" +\n                \"id=\" + id +\n                \", name=\" + name +\n                \", permissionUrl=\" + permissionUrl +\n                \", method=\" + method +\n                \", description=\" + description +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/bean/Role.java",
    "content": "package com.yy.example.bean;\n\n\n\npublic class Role implements Comparable<Role>{\n\tprivate Integer id;\n\tprivate String name;\n\tprivate Integer roleLevel;\n\tprivate String description;\n\tprivate String menuItems;\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\tpublic Integer getRoleLevel() {\n\t\treturn roleLevel;\n\t}\n\tpublic void setRoleLevel(Integer roleLevel) {\n\t\tthis.roleLevel = roleLevel;\n\t}\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\tpublic String getMenuItems() {\n\t\treturn menuItems;\n\t}\n\n\tpublic void setMenuItems(String menuItems) {\n\t\tthis.menuItems = menuItems;\n\t}\n\n\t@Override\n\tpublic int compareTo(Role o) {\n\t\tif(id == o.getId()){\n\t\t\treturn 0;\n\t\t}else if(id > o.getId()){\n\t\t\treturn 1;\n\t\t}else{\n\t\t\treturn -1;\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\t// TODO Auto-generated method stub\n\t\tif(obj instanceof Role){\n\t\t\tif(this.id == ((Role)obj).getId()){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Role{\" +\n\t\t\t\"id=\" + id +\n\t\t\t\", name=\" + name +\n\t\t\t\", roleLevel=\" + roleLevel +\n\t\t\t\", description=\" + description +\n\t\t\t'}';\n\t\t}\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/bean/User.java",
    "content": "package com.yy.example.bean;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.Collection;\nimport java.util.List;\n\npublic class User implements UserDetails {\n    private Integer id;\n    private String cnname;\n    private String username;\n    @JsonIgnore\n    private String password;\n    private String rePassword;\n    private String historyPassword;\n    private String email;\n    @JsonIgnore\n    private String telephone;\n    private String mobilePhone;\n    private List<? extends GrantedAuthority> authorities;\n    private Role role;\n    private Integer roleId;\n\n\n    @Override\n    @JsonIgnore\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @Override\n    @JsonIgnore\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    @JsonIgnore\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    @JsonIgnore\n    public boolean isEnabled() {\n        return true;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    @JsonIgnore\n    public Collection<? extends GrantedAuthority> getAuthorities() {\n        return authorities;\n    }\n\n    public void setGrantedAuthorities(List<? extends GrantedAuthority> authorities) {\n        this.authorities = authorities;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getCnname() {\n        return cnname;\n    }\n\n    public void setCnname(String cnname) {\n        this.cnname = cnname;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getTelephone() {\n        return telephone;\n    }\n\n    public void setTelephone(String telephone) {\n        this.telephone = telephone;\n    }\n\n    public String getMobilePhone() {\n        return mobilePhone;\n    }\n\n    public void setMobilePhone(String mobilePhone) {\n        this.mobilePhone = mobilePhone;\n    }\n\n    public String getRePassword() {\n        return rePassword;\n    }\n\n    public void setRePassword(String rePassword) {\n        this.rePassword = rePassword;\n    }\n\n    public String getHistoryPassword() {\n        return historyPassword;\n    }\n\n    public void setHistoryPassword(String historyPassword) {\n        this.historyPassword = historyPassword;\n    }\n\n    public Role getRole() {\n        return role;\n    }\n\n    public void setRole(Role role) {\n        this.role = role;\n    }\n\n    public Integer getRoleId() {\n        return roleId;\n    }\n\n    public void setRoleId(Integer roleId) {\n        this.roleId = roleId;\n    }\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id=\" + id +\n                \", cnname=\" + cnname +\n                \", username=\" + username +\n                \", password=\" + password +\n                \", email=\" + email +\n                \", telephone=\" + telephone +\n                \", mobilePhone=\" + mobilePhone +\n                '}';\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/DataSourceConfig.java",
    "content": "package com.yy.example.config;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport java.beans.PropertyVetoException;\n\n@Configuration\npublic class DataSourceConfig {\n\t@Autowired\n    private Environment env;\n\t\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"jdbc.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"jdbc.url\"));\n        dataSource.setUser(env.getProperty(\"jdbc.username\"));\n        dataSource.setPassword(env.getProperty(\"jdbc.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n        \n        return dataSource;\n    }\n    \n    \n}\n\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/MapperScannerConfig.java",
    "content": "package com.yy.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MapperScannerConfig {\n\n\t@Bean\n\tpublic MapperScannerConfigurer mapperScannerConfigurer() {\n\t\tMapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n\t\tmapperScannerConfigurer.setBasePackage(\"**.dao\");\n\t\tmapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n\t\treturn mapperScannerConfigurer;\n\t}\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/MyBatisConfig.java",
    "content": "package com.yy.example.config;\n\nimport org.apache.ibatis.type.JdbcType;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n@Configuration\npublic class MyBatisConfig {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Bean(name = \"sqlSessionFactory\")\n\tpublic SqlSessionFactoryBean sqlSessionFactory(\n\t\t\tApplicationContext applicationContext) throws Exception {\n\t\tSqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n\t\tsessionFactory.setDataSource(dataSource);\n\n\t\torg.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();\n\t\tconfiguration.setMapUnderscoreToCamelCase(true);\n\t\tconfiguration.setJdbcTypeForNull(JdbcType.NULL);\n\t\tconfiguration.setLogImpl(org.apache.ibatis.logging.log4j.Log4jImpl.class);//use log4j log\n\t\tsessionFactory.setConfiguration(configuration);\n\t\tsessionFactory.setMapperLocations(applicationContext.getResources(\"classpath:com/yy/example/mapper/*.xml\"));\n//\n//\t\tProperties prop = new Properties();\n//\t\tprop.setProperty(\"supportMethodsArguments\",\"true\");\n//\t\tprop.setProperty(\"rowBoundsWithCount\", \"true\");\n//\t\tprop.setProperty(\"params\",\"pageNum=pageNum;pageSize=pageSize;\");\n//\t\tPageInterceptor pi = new PageInterceptor();\n//\t\tpi.setProperties(prop);\n//\t\tsessionFactory.setPlugins(new Interceptor[]{pi});\n\n\t\treturn sessionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/MyBatisScannerConfig.java",
    "content": "package com.yy.example.config;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyBatisScannerConfig {\n    @Bean\n    public MapperScannerConfigurer MapperScannerConfigurer() {\n        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n        mapperScannerConfigurer.setBasePackage(\"com.us.example.dao\");\n        mapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n        return mapperScannerConfigurer;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/TransactionConfig.java",
    "content": "package com.yy.example.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\nimport javax.sql.DataSource;\n\n@Configuration\n@ComponentScan\npublic class TransactionConfig implements TransactionManagementConfigurer{\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean(name = \"transactionManager\")\n    @Override\n    public PlatformTransactionManager annotationDrivenTransactionManager() {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/config/WebSecurityConfig.java",
    "content": "package com.yy.example.config;\n\n\nimport com.yy.example.security.UrlUserService;\nimport com.yy.example.utils.MD5Util;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.core.session.SessionRegistry;\nimport org.springframework.security.core.session.SessionRegistryImpl;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n\n/**\n * <Description> <br>\n *\n * @author henley<br>\n * @version 1.0<br>\n * @taskId <br>\n * @CreateDate 2017年1月13日 <br>\n */\n@Configuration\n@EnableWebSecurity\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n    private UrlUserService urlUserService;\n    @Autowired\n    SessionRegistry sessionRegistry;\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n                .csrf().disable()\n                .authorizeRequests()\n                .antMatchers(\"/login\").permitAll()\n                .antMatchers(\"/logout\").permitAll()\n                .antMatchers(\"/images/**\").permitAll()\n                .antMatchers(\"/js/**\").permitAll()\n                .antMatchers(\"/css/**\").permitAll()\n                .antMatchers(\"/fonts/**\").permitAll()\n                .antMatchers(\"/favicon.ico\").permitAll()\n                .antMatchers(\"/\").permitAll()\n                .anyRequest().authenticated()\n                .and()\n                .sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry)\n                .and()\n                .and()\n                .logout()\n                .invalidateHttpSession(true)\n                .clearAuthentication(true)\n                .and()\n                .httpBasic();\n    }\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(urlUserService).passwordEncoder(new PasswordEncoder() {\n\n            @Override\n            public String encode(CharSequence rawPassword) {\n                return MD5Util.encode((String) rawPassword);\n            }\n\n            @Override\n            public boolean matches(CharSequence rawPassword, String encodedPassword) {\n                return encodedPassword.equals(MD5Util.encode((String) rawPassword));\n            }\n        });\n    }\n\n    @Bean\n    public SessionRegistry getSessionRegistry(){\n        SessionRegistry sessionRegistry=new SessionRegistryImpl();\n        return sessionRegistry;\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/controller/LoginController.java",
    "content": "package com.yy.example.controller;\n\n\nimport com.yy.example.bean.User;\nimport com.yy.example.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n\n@Controller\npublic class LoginController {\n    @Autowired\n    UserService userService;\n\n    @RequestMapping(value = \"/login\")\n    @ResponseBody\n    public Object login(@AuthenticationPrincipal User loginedUser, @RequestParam(name = \"logout\", required = false) String logout) {\n        if (logout != null) {\n            return null;\n        }\n        if (loginedUser != null) {\n            return userService.getById(loginedUser.getId());\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/controller/UserController.java",
    "content": "package com.yy.example.controller;\n\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.servlet.http.HttpServletRequest;\n\n@RequestMapping(value = \"/users\")\n@RestController\npublic class UserController {\n\n\n\t@RequestMapping(method = RequestMethod.GET)\n    @ResponseBody\n    public Object list(HttpServletRequest request) {\n\t\treturn \"Get all User\";\n    }\n\n\t\n\t@RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n    @ResponseBody\n    public Object detail(@PathVariable Integer id) {\n\t\treturn \"Get a user\";\n    }\n    \n    @RequestMapping(method = RequestMethod.POST)\n    @ResponseBody\n    public Object create(HttpServletRequest request) {\n\t\treturn \"POST a user\";\n    }\n\n    @RequestMapping(method = RequestMethod.PUT)\n    @ResponseBody\n    public Object update(HttpServletRequest request) {\n\t\treturn \"PUT a user\";\n    }\n\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/dao/PermissionDao.java",
    "content": "package com.yy.example.dao;\n\n\nimport com.yy.example.bean.Permission;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface PermissionDao {\n\n    List<Permission> getByMap(Map<String, Object> map);\n\n    Permission getById(Integer id);\n\n    Integer create(Permission permission);\n\n    int update(Permission permission);\n\n    List<Permission> getByUserId(Integer userId);\n\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/dao/UserDao.java",
    "content": "package com.yy.example.dao;\n\n\nimport com.yy.example.bean.User;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface UserDao {\n\n\tList<User> getByMap(Map<String, Object> map);\n\tList<User> getByRoleId(Map<String, Object> map);\n\tUser getById(Integer id);\n\tInteger create(User user);\n\tint update(User user);\n\tUser getByUserName(String userName);\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlAccessDecisionManager.java",
    "content": "package com.yy.example.security;\n\nimport org.springframework.security.access.AccessDecisionManager;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.authentication.InsufficientAuthenticationException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Collection;\n\n\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class UrlAccessDecisionManager implements AccessDecisionManager {\n    @Override\n    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {\n        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();\n        String url, method;\n        if (\"anonymousUser\".equals(authentication.getPrincipal())\n                || matchers(\"/images/**\", request)\n                || matchers(\"/js/**\", request)\n                || matchers(\"/css/**\", request)\n                || matchers(\"/fonts/**\", request)\n                || matchers(\"/\", request)\n                || matchers(\"/index.html\", request)\n                || matchers(\"/favicon.ico\", request)\n                || matchers(\"/login\", request)) {\n            return;\n        } else {\n            for (GrantedAuthority ga : authentication.getAuthorities()) {\n                if (ga instanceof UrlGrantedAuthority) {\n                    UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) ga;\n                    url = urlGrantedAuthority.getPermissionUrl();\n                    method = urlGrantedAuthority.getMethod();\n                    if (matchers(url, request)) {\n                        if (method.equals(request.getMethod()) || \"ALL\".equals(method)) {\n                            return;\n                        }\n                    }\n                }\n            }\n        }\n        throw new AccessDeniedException(\"no right\");\n    }\n\n\n    @Override\n    public boolean supports(ConfigAttribute attribute) {\n        return true;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n\n\n    private boolean matchers(String url, HttpServletRequest request) {\n        AntPathRequestMatcher matcher = new AntPathRequestMatcher(url);\n        if (matcher.matches(request)) {\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlConfigAttribute.java",
    "content": "package com.yy.example.security;\n\nimport org.springframework.security.access.ConfigAttribute;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * Created by yangyibo on 17/2/15.\n */\npublic class UrlConfigAttribute implements ConfigAttribute {\n\n    private final HttpServletRequest httpServletRequest;\n\n    public UrlConfigAttribute(HttpServletRequest httpServletRequest) {\n        this.httpServletRequest = httpServletRequest;\n    }\n\n\n    @Override\n    public String getAttribute() {\n        return null;\n    }\n\n    public HttpServletRequest getHttpServletRequest() {\n        return httpServletRequest;\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlFilterSecurityInterceptor.java",
    "content": "package com.yy.example.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.SecurityMetadataSource;\nimport org.springframework.security.access.intercept.AbstractSecurityInterceptor;\nimport org.springframework.security.access.intercept.InterceptorStatusToken;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.*;\nimport java.io.IOException;\n\n/**\n * Created by yangyibo on 17/2/7.\n */\n@Service\npublic class UrlFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {\n\n\n    @Autowired\n    private FilterInvocationSecurityMetadataSource securityMetadataSource;\n\n    @Autowired\n    public void setUrlAccessDecisionManager(UrlAccessDecisionManager urlAccessDecisionManager) {\n        super.setAccessDecisionManager(urlAccessDecisionManager);\n    }\n\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\n        FilterInvocation fi = new FilterInvocation(request, response, chain);\n        invoke(fi);\n    }\n\n\n    public void invoke(FilterInvocation fi) throws IOException, ServletException {\n        //fi里面有一个被拦截的url\n        //里面调用UrlMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限\n        //再调用UrlAccessDecisionManager的decide方法来校验用户的权限是否足够\n        InterceptorStatusToken token = super.beforeInvocation(fi);\n        try {\n            //执行下一个拦截器\n            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());\n        } finally {\n            super.afterInvocation(token, null);\n        }\n    }\n\n\n    @Override\n    public void destroy() {\n\n    }\n\n    @Override\n    public Class<?> getSecureObjectClass() {\n        return FilterInvocation.class;\n\n    }\n\n    @Override\n    public SecurityMetadataSource obtainSecurityMetadataSource() {\n        return this.securityMetadataSource;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlGrantedAuthority.java",
    "content": "package com.yy.example.security;\n\nimport org.springframework.security.core.GrantedAuthority;\n\n/**\n * Created by yangyibo on 17/2/15.\n */\npublic class UrlGrantedAuthority implements GrantedAuthority {\n\n    private String permissionUrl;\n    private String method;\n\n    public String getPermissionUrl() {\n        return permissionUrl;\n    }\n\n    public void setPermissionUrl(String permissionUrl) {\n        this.permissionUrl = permissionUrl;\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public UrlGrantedAuthority (String permissionUrl, String method) {\n        this.permissionUrl = permissionUrl;\n        this.method = method;\n    }\n\n    @Override\n    public String getAuthority() {\n        return this.permissionUrl + \";\"+this.method;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlMetadataSourceService.java",
    "content": "package com.yy.example.security;\n\nimport org.springframework.security.access.ConfigAttribute;\nimport org.springframework.security.web.FilterInvocation;\nimport org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Created by yangyibo on 17/1/19.\n */\n@Service\npublic class UrlMetadataSourceService implements\n        FilterInvocationSecurityMetadataSource {\n\n    @Override\n    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {\n        final HttpServletRequest request = ((FilterInvocation) object).getRequest();\n        Set<ConfigAttribute> allAttributes = new HashSet<>();\n        ConfigAttribute configAttribute = new UrlConfigAttribute(request);\n        allAttributes.add(configAttribute);\n        return allAttributes;\n    }\n\n    @Override\n    public Collection<ConfigAttribute> getAllConfigAttributes() {\n        return null;\n    }\n\n    @Override\n    public boolean supports(Class<?> clazz) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/security/UrlUserService.java",
    "content": "package com.yy.example.security;\n\nimport com.yy.example.bean.Permission;\nimport com.yy.example.bean.User;\nimport com.yy.example.dao.PermissionDao;\nimport com.yy.example.dao.UserDao;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by yangyibo on 17/2/7.\n */\n@Service\npublic class UrlUserService implements UserDetailsService {\n    @Autowired\n    UserDao userDao;\n    @Autowired\n    PermissionDao permissionDao;\n    @Override\n    public UserDetails loadUserByUsername(String userName) { //重写loadUserByUsername 方法获得 userdetails 类型用户\n\n        User user = userDao.getByUserName(userName);\n        if (user != null) {\n            List<Permission> permissions = permissionDao.getByUserId(user.getId());\n            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();\n            for (Permission permission : permissions) {\n                if (permission != null && permission.getName()!=null) {\n                    GrantedAuthority grantedAuthority = new UrlGrantedAuthority(permission.getPermissionUrl(),permission.getMethod());\n                    grantedAuthorities.add(grantedAuthority);\n                }\n            }\n            user.setGrantedAuthorities(grantedAuthorities);\n            return user;\n        } else {\n            throw new UsernameNotFoundException(\"admin: \" + userName + \" do not exist!\");\n        }\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/service/UserService.java",
    "content": "package com.yy.example.service;\n\nimport com.yy.example.bean.User;\nimport com.yy.example.dao.UserDao;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport org.springframework.security.core.session.SessionRegistry;\nimport org.springframework.stereotype.Service;\n\n\n@Service\npublic class UserService {\n\t@Autowired\n\tprivate SessionRegistry sessionRegistry;\n\n\t@Autowired\n\tprivate UserDao userDao;\n\n\tpublic User getById(Integer id) {\n\t\tUser user = userDao.getById(id);\n\t\treturn user;\n\t}\n\t\n\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/java/com/yy/example/utils/MD5Util.java",
    "content": "package com.yy.example.utils;\n\n/**\n * Created by yangyibo on 17/2/7.\n */\nimport java.security.MessageDigest;\n\n/**\n * MD5加密工具\n *\n */\npublic class MD5Util {\n\n    private static final String SALT = \"yy\";\n   \n    private static final String WECAHT_SALT=\"yy_aa\";\n    \n    public static String encode(String password) {\n        password = password + SALT;\n        return processEncode(password);\n    }\n    \n    /**\n     * 与微信模块约定的加密模块\n     * */\n    public static String wechatEncode(String password){\n    \tpassword = password + WECAHT_SALT;\n        return processEncode(password);\n    }\n    \n    public static boolean wehcatValidation(String str, String token){\n\t\tboolean flag = false;\n\t\tif(wechatEncode(str).equals(token)){\n\t\t\tflag = true;\n\t\t}\n\t\treturn flag;\n\t}\n\n    public static String processEncode(String password) {\n        MessageDigest md5 = null;\n        try {\n            md5 = MessageDigest.getInstance(\"MD5\");\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n        char[] charArray = password.toCharArray();\n        byte[] byteArray = new byte[charArray.length];\n\n        for (int i = 0; i < charArray.length; i++)\n            byteArray[i] = (byte) charArray[i];\n        byte[] md5Bytes = md5.digest(byteArray);\n        StringBuffer hexValue = new StringBuffer();\n        for (int i = 0; i < md5Bytes.length; i++) {\n            int val = ((int) md5Bytes[i]) & 0xff;\n            if (val < 16) {\n                hexValue.append(\"0\");\n            }\n\n            hexValue.append(Integer.toHexString(val));\n        }\n        return hexValue.toString();\n    }\n\n    \t\n    public static void main(String[] args) {\n        System.out.println(MD5Util.encode(\"abel\"));\n        System.out.println(MD5Util.encode(\"admin\"));\n    }\n}"
  },
  {
    "path": "springboot-springSecurity4/src/main/resources/application.properties",
    "content": "jdbc.driverClassName=com.mysql.jdbc.Driver\r\njdbc.url=jdbc:mysql://localhost:3306/epp_manager?useSSL=false&useUnicode=true&characterEncoding=UTF-8\r\n#jdbc.url=jdbc:mysql://47.94.17.188:3306/epp_manager?useSSL=false&useUnicode=true&characterEncoding=UTF-8\r\njdbc.username=root\r\njdbc.password=admin\r\nserver.port=8088\r\nlogging.level.org.springframework.security= INFO\r\nspring.thymeleaf.cache=false\r\n"
  },
  {
    "path": "springboot-springSecurity4/src/main/resources/com/yy/example/mapper/PermissionDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.yy.example.dao.PermissionDao\">\n    <resultMap id=\"permissionMap\" type=\"com.yy.example.bean.Permission\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"name\" column=\"name\"/>\n\t\t<result property=\"permissionUrl\" column=\"permission_url\"/>\n\t\t<result property=\"method\" column=\"method\"/>\n\t\t<result property=\"description\" column=\"description\"/>\n\n    </resultMap>\n\n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"name != null and name != ''\">\n\t\t\t\tand name = #{name}\n\t\t\t</if>\n\t\t\t<if test=\"permissionUrl != null and permissionUrl != ''\">\n\t\t\t\tand permission_url = #{permissionUrl}\n\t\t\t</if>\n\t\t\t<if test=\"method != null and method != ''\">\n\t\t\t\tand method = #{method}\n\t\t\t</if>\n\t\t\t<if test=\"description != null and description != ''\">\n\t\t\t\tand description = #{description}\n\t\t\t</if>\n\n        </where>\n    </sql>\n\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission\n\t\t<include refid=\"queryCondition\" />\n    </select>\n\n    <select id=\"getById\" parameterType=\"int\" resultMap=\"permissionMap\">\n    \tSELECT * FROM permission WHERE id =#{id}\n    </select>\n\n\t<select id=\"getList\"  resultMap=\"permissionMap\">\n\t\tSELECT * from permission\n\t</select>\n\n\t<select id=\"getByUserId\" parameterType=\"int\" resultMap=\"permissionMap\">\n\t\tselect p.*\n\t\tfrom user u\n\t\tLEFT JOIN user_role ur on u.id= ur.User_id\n\t\tLEFT JOIN role r on ur.role_id=r.id\n\t\tLEFT JOIN role_permission rp on rp.role_id=r.id\n\t\tLEFT JOIN permission p on p.id =rp.permission_id\n\t\twhere u.id=#{userId}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"com.yy.example.bean.Permission\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO permission(\n\t\t\tid,\n\t\t\tname,\n\t\t\tpermission_url,\n\t\t    method,\n\t\t\tdescription\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{name},\n\t\t\t#{permissionUrl},\n\t\t    #{method},\n\t\t\t#{description}\n\t\t)\n    </insert>\n\n    <update id=\"update\" parameterType=\"com.yy.example.bean.Permission\">\n\t\tUPDATE permission SET\n\t\t\tname = #{name},\n\t\t\tpermission_url = #{permissionUrl},\n\t\t\tmethod = #{method},\n\t\t\tdescription = #{description}\n\t\tWHERE id = #{id}\n    </update>\n\n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM permission WHERE id = #{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "springboot-springSecurity4/src/main/resources/com/yy/example/mapper/UserDaoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>  \n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"> \n<mapper namespace=\"com.yy.example.dao.UserDao\">\n    <resultMap id=\"userMap\" type=\"com.yy.example.bean.User\">\n\t\t<id property=\"id\" column=\"id\"/>\n\t\t<result property=\"cnname\" column=\"cnname\"/>\n\t\t<result property=\"username\" column=\"username\"/>\n\t\t<result property=\"password\" column=\"password\"/>\n\t\t<result property=\"email\" column=\"email\"/>\n\t\t<result property=\"telephone\" column=\"telephone\"/>\n\t\t<result property=\"mobilePhone\" column=\"mobile_phone\"/>\n    </resultMap>\n\n    \n    <sql id=\"queryCondition\">\n        <where>\n\t\t\t<if test=\"id != null and id != ''\">\n\t\t\t\tand id = #{id}\n\t\t\t</if>\n\t\t\t<if test=\"cnname != null and cnname != ''\">\n\t\t\t\tand cnname = #{cnname}\n\t\t\t</if>\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tand username = #{username}\n\t\t\t</if>\n\t\t\t<if test=\"password != null and password != ''\">\n\t\t\t\tand password = #{password}\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\t\tand email = #{email}\n\t\t\t</if>\n\t\t\t<if test=\"telephone != null and telephone != ''\">\n\t\t\t\tand telephone = #{telephone}\n\t\t\t</if>\n\t\t\t<if test=\"mobilePhone != null and mobilePhone != ''\">\n\t\t\t\tand mobile_phone = #{mobilePhone}\n\t\t\t</if>\n\t\t</where>\n    </sql>\n    \t\n    <select id=\"getByMap\" parameterType=\"map\" resultMap=\"userMap\">\n    \tSELECT u.* FROM user u\n\t\t<include refid=\"queryCondition\" />\n\t\tORDER  by id DESC \n    </select>\n\n    \n    <select id=\"getById\" parameterType=\"int\" resultMap=\"userMap\">\n    \tSELECT * FROM user WHERE id =#{id}\n    </select>\n\n\t<select id=\"getByUserName\" parameterType=\"String\" resultMap=\"userMap\">\n\t\tselect u.* from user u\n\t\twhere username= #{username}\n\t</select>\n\n\t<insert id=\"create\" parameterType=\"com.yy.example.bean.User\">\n        <selectKey resultType=\"int\"  order=\"AFTER\" keyProperty=\"id\" >\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t</selectKey>\n\t\tINSERT INTO user(\n\t\t\tid,\n\t\t\tcnname,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\temail,\n\t\t\ttelephone,\n\t\t\tmobile_phone,\n\t\t\twechat_id,\n\t\t\tskill,\n\t\t\tdepartment_id,\n\t\t\tlogin_count\n\t\t)VALUES(\n\t\t\t#{id},\n\t\t\t#{cnname},\n\t\t\t#{username},\n\t\t\t#{password},\n\t\t\t#{email},\n\t\t\t#{telephone},\n\t\t\t#{mobilePhone},\n\t\t\t#{wechatId},\n\t\t\t#{skill},\n\t\t\t#{departmentId},\n\t\t\t#{loginCount}\n\t\t)\n    </insert>\n    \n    <update id=\"update\" parameterType=\"com.yy.example.bean.User\">\n\t\tUPDATE user \n\t\t  <set>\n\t\t\t<if test = \"cnname != null and cnname != ''\">\t\n\t\t\tcnname = #{cnname},\n\t\t\t</if>\n\t\t\t<if test = \"password != null and password != ''\">\n\t\t\tpassword = #{password},\n\t\t\t</if>\n\t\t\t<if test=\"email != null and email != ''\">\n\t\t\temail = #{email},\n\t\t\t</if>\n\t\t\t<if test=\"telephone != null and telephone != ''\">\t\t\n\t\t\ttelephone = #{telephone},\n\t\t\t</if>\n\t\t\t<if test=\" mobilePhone!= null and mobilePhone != ''\">\n\t\t\tmobile_phone = #{mobilePhone},\n\t\t\t</if>\n\t\t </set>\t\t\t\n\t\tWHERE id = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"int\">\n    \tDELETE FROM user WHERE id = #{id}\n    </delete>\n        \n</mapper>"
  },
  {
    "path": "springboot-swagger-ui/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.abel</groupId>\n    <artifactId>springboot-swagger-ui</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.3.0.RELEASE</version>\n    </parent>\n\n    <properties>\n        <start-class>com.abel.Application</start-class>\n\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n    </properties>\n\n    <!-- springboot -->\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n\n        <!--db-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>6.0.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>commons-logging</groupId>\n                    <artifactId>commons-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!--util-->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n\n        <!--swagger2-->\n        <dependency>\n\n            <groupId>io.springfox</groupId>\n\n            <artifactId>springfox-swagger2</artifactId>\n\n            <version>2.2.2</version>\n\n        </dependency>\n\n        <dependency>\n\n            <groupId>io.springfox</groupId>\n\n            <artifactId>springfox-swagger-ui</artifactId>\n\n            <version>2.2.2</version>\n\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/Application.java",
    "content": "package com.abel.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport static org.springframework.boot.SpringApplication.run;\n\n/**\n * Created by yangyibo on 17/1/17.\n */\n\n@ComponentScan(basePackages =\"com.abel.example\")\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n    public static void main(String[] args) {\n        ConfigurableApplicationContext run = run(Application.class, args);\n    }\n\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/Swagger2.java",
    "content": "package com.abel.example;\n\nimport org.springframework.context.annotation.Bean;\n\nimport org.springframework.context.annotation.Configuration;\nimport springfox.documentation.builders.ApiInfoBuilder;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\n/**\n * Created by yangyibo on 2018/9/7.\n */\n@Configuration\n@EnableSwagger2\npublic class Swagger2 {\n    /**\n     * 创建API应用\n     * apiInfo() 增加API相关信息\n     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现，\n     * 本例采用指定扫描的包路径来定义指定要建立API的目录。\n     *\n     * @return\n     */\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.abel.example.controller\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    /**\n     * 创建该API的基本信息（这些基本信息会展现在文档页面中）\n     * 访问地址：http://项目实际地址/swagger-ui.html\n     * @return\n     */\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Spring Boot中使用Swagger2构建RESTful APIs\")\n                .description(\"更多请关注https://blog.csdn.net/u012373815\")\n                .termsOfServiceUrl(\"https://blog.csdn.net/u012373815\")\n                .contact(\"abel\")\n                .version(\"1.0\")\n                .build();\n    }\n}\n"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/bean/User.java",
    "content": "package com.abel.example.bean;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\n@Entity\n@Table(name = \"sec_user\")\npublic class User {\n    @Id\n    @GeneratedValue\n    private Long id;\n    @Column(name = \"name\")\n    private String name;\n    @Column(name = \"password\")\n    private String password;\n    @Column(name = \"username\")\n    private String username;\n    @Column(name = \"email\")\n    private String email;\n    @Column(name = \"mobilephone\")\n    private String mobilephone;\n    @Column(name = \"telephone\")\n    private String telephone;\n    @Column(name = \"user_type\")\n    private Integer userType;\n    @Column(name = \"create_by\")\n    private String createBy;\n    @Column(name = \"create_time\")\n    private Date createTime;\n    @Column(name = \"update_by\")\n    private String updateBy;\n    @Column(name = \"update_time\")\n    private Date updateTime;\n    @Column(name = \"disabled\")\n    private Integer disabled;\n\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @JsonIgnore\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getMobilephone() {\n        return mobilephone;\n    }\n\n    public void setMobilephone(String mobilephone) {\n        this.mobilephone = mobilephone;\n    }\n\n    public String getTelephone() {\n        return telephone;\n    }\n\n    public void setTelephone(String telephone) {\n        this.telephone = telephone;\n    }\n\n    public Integer getUserType() {\n        return userType;\n    }\n\n    public void setUserType(Integer userType) {\n        this.userType = userType;\n    }\n\n    public String getCreateBy() {\n        return createBy;\n    }\n\n    public void setCreateBy(String createBy) {\n        this.createBy = createBy;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public String getUpdateBy() {\n        return updateBy;\n    }\n\n    public void setUpdateBy(String updateBy) {\n        this.updateBy = updateBy;\n    }\n\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n\n    public Integer getDisabled() {\n        return disabled;\n    }\n\n    public void setDisabled(Integer disabled) {\n        this.disabled = disabled;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/config/DBConfig.java",
    "content": "package com.abel.example.config;\n\nimport java.beans.PropertyVetoException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n    @Autowired\n    private Environment env;\n\n\n    @Bean(name=\"dataSource\")\n    public ComboPooledDataSource dataSource() throws PropertyVetoException {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setDriverClass(env.getProperty(\"ms.db.driverClassName\"));\n        dataSource.setJdbcUrl(env.getProperty(\"ms.db.url\"));\n        dataSource.setUser(env.getProperty(\"ms.db.username\"));\n        dataSource.setPassword(env.getProperty(\"ms.db.password\"));\n        dataSource.setMaxPoolSize(20);\n        dataSource.setMinPoolSize(5);\n        dataSource.setInitialPoolSize(10);\n        dataSource.setMaxIdleTime(300);\n        dataSource.setAcquireIncrement(5);\n        dataSource.setIdleConnectionTestPeriod(60);\n\n        return dataSource;\n    }\n\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/config/JpaConfig.java",
    "content": "package com.abel.example.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n@Configuration\n@EnableJpaRepositories(\"com.abel.example.dao\")\n@EnableTransactionManagement\n@ComponentScan\npublic class JpaConfig {\n\n    @Autowired\n    private DataSource dataSource;\n\n    @Bean\n    public EntityManagerFactory entityManagerFactory() {\n        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();\n        //vendorAdapter.setShowSql(true);\n        //vendorAdapter.setGenerateDdl(true);\n\n        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();\n        factory.setJpaVendorAdapter(vendorAdapter);\n        factory.setPackagesToScan(\"com.abel.example.bean\");\n        factory.setDataSource(dataSource);\n\n\n        Map<String, Object> jpaProperties = new HashMap<String, Object>();\n        jpaProperties.put(\"hibernate.ejb.naming_strategy\",\"org.hibernate.cfg.ImprovedNamingStrategy\");\n        jpaProperties.put(\"hibernate.jdbc.batch_size\",50);\n        //jpaProperties.put(\"hibernate.show_sql\",true);\n\n        factory.setJpaPropertyMap(jpaProperties);\n        factory.afterPropertiesSet();\n        return factory.getObject();\n    }\n\n    @Bean\n    public PlatformTransactionManager transactionManager() {\n\n        JpaTransactionManager txManager = new JpaTransactionManager();\n        txManager.setEntityManagerFactory(entityManagerFactory());\n        return txManager;\n    }\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/controller/UserController.java",
    "content": "package com.abel.example.controller;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Map;\n\nimport com.abel.example.bean.User;\nimport io.swagger.annotations.*;\nimport org.apache.log4j.Logger;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\n\nimport com.abel.example.service.UserService;\nimport com.abel.example.util.CommonUtil;\n\n\n@Controller\n@RequestMapping(value = \"/users\")\n@Api(value = \"用户的增删改查\")\npublic class UserController {\n\n    @Autowired\n    private UserService userService;\n\n\n    /**\n     * 查询所有的用户\n     * api :localhost:8099/users\n     * @return\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    @ResponseBody\n    @ApiOperation(value = \"获取用户列表，目前没有分页\")\n    public ResponseEntity<Object> findAll() {\n        return new ResponseEntity<>(userService.listUsers(), HttpStatus.OK);\n    }\n\n    /**\n     * 通过id 查找用户\n     * api :localhost:8099/users/1\n     * @param id\n     * @return\n     */\n    @RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n    @ResponseBody\n    @ApiOperation(value = \"通过id获取用户信息\", notes=\"返回用户信息\")\n    public ResponseEntity<Object> getUserById(@PathVariable Integer id) {\n        return new ResponseEntity<>(userService.getUserById(Long.valueOf(id)), HttpStatus.OK);\n    }\n\n\n    /**\n     * 通过spring data jpa 调用方法\n     * api :localhost:8099/users/byname?username=xxx\n     * 通过用户名查找用户\n     * @param request\n     * @return\n     */\n    @RequestMapping(value = \"/byname\", method = RequestMethod.GET)\n    @ResponseBody\n    @ApiImplicitParam(paramType = \"query\",name= \"username\" ,value = \"用户名\",dataType = \"string\")\n    @ApiOperation(value = \"通过用户名获取用户信息\", notes=\"返回用户信息\")\n    public ResponseEntity<Object> getUserByUserName(HttpServletRequest request) {\n        Map<String, Object> map = CommonUtil.getParameterMap(request);\n        String username = (String) map.get(\"username\");\n        return new ResponseEntity<>(userService.getUserByUserName(username), HttpStatus.OK);\n    }\n\n    /**\n     * 通过spring data jpa 调用方法\n     * api :localhost:8099/users/byUserNameContain?username=xxx\n     * 通过用户名模糊查询\n     * @param request\n     * @return\n     */\n    @RequestMapping(value = \"/byUserNameContain\", method = RequestMethod.GET)\n    @ResponseBody\n    @ApiImplicitParam(paramType = \"query\",name= \"username\" ,value = \"用户名\",dataType = \"string\")\n    @ApiOperation(value = \"通过用户名模糊搜索用户信息\", notes=\"返回用户信息\")\n    public ResponseEntity<Object> getUsers(HttpServletRequest request) {\n        Map<String, Object> map = CommonUtil.getParameterMap(request);\n        String username = (String) map.get(\"username\");\n        return new ResponseEntity<>(userService.getByUsernameContaining(username), HttpStatus.OK);\n    }\n\n\n    /**\n     * 添加用户啊\n     * api :localhost:8099/users\n     *\n     * @param user\n     * @return\n     */\n    @RequestMapping(method = RequestMethod.POST)\n    @ResponseBody\n    @ApiModelProperty(value=\"user\",notes = \"用户信息的json串\")\n    @ApiOperation(value = \"新增用户\", notes=\"返回新增的用户信息\")\n    public ResponseEntity<Object> saveUser(@RequestBody User user) {\n        return new ResponseEntity<>(userService.saveUser(user), HttpStatus.OK);\n    }\n\n    /**\n     * 修改用户信息\n     * api :localhost:8099/users\n     * @param user\n     * @return\n     */\n    @RequestMapping(method = RequestMethod.PUT)\n    @ResponseBody\n    @ApiModelProperty(value=\"user\",notes = \"修改后用户信息的json串\")\n    @ApiOperation(value = \"新增用户\", notes=\"返回新增的用户信息\")\n    public ResponseEntity<Object> updateUser(@RequestBody User user) {\n        return new ResponseEntity<>(userService.updateUser(user), HttpStatus.OK);\n    }\n\n    /**\n     * 通过ID删除用户\n     * api :localhost:8099/users/2\n     * @param id\n     * @return\n     */\n    @RequestMapping(value = \"/{id}\", method = RequestMethod.DELETE)\n    @ResponseBody\n    @ApiOperation(value = \"通过id删除用户信息\", notes=\"返回删除状态1 成功 0 失败\")\n    public ResponseEntity<Object> deleteUser(@PathVariable Integer id) {\n        return new ResponseEntity<>(userService.removeUser(id.longValue()), HttpStatus.OK);\n    }\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/dao/UserJpaDao.java",
    "content": "package com.abel.example.dao;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\n\nimport com.abel.example.bean.User;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.query.Param;\n\nimport java.util.List;\n\n/**\n * The Interface UserJpaDao.\n *\n * @author abel\n */\npublic interface UserJpaDao extends JpaRepository<User, Long> {\n\n    /**\n     * Find by name.\n     *\n     * @param name the name\n     * @return the user\n     */\n    User findByName(String name);\n\n    User getOne(Long id);\n\n    List<User> findByUsernameContaining(String username);\n\n    User getByUsernameIs(String username);\n\n    @Query(\"select s from User s where name like CONCAT('%',:name,'%')\")\n    List<User> findByNameLike(@Param(\"name\") String name);\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/service/UserService.java",
    "content": "package com.abel.example.service;\n\nimport java.util.List;\n\nimport com.abel.example.bean.User;\n\n/**\n * The Interface UserService.\n */\npublic interface UserService {\n\n\t/**\n\t * Gets the user by name.\n\t *\n\t * @param username the user name\n\t * @return the user by name\n\t */\n\tpublic User getUserByUserName(String username);\n\n\tpublic List<User> getByUsernameContaining(String username);\n\n\t/**\n\t * 增加学生\n\t * @param user\n\t * @return\n\t */\n\tUser saveUser(User user);\n\n\t/**\n\t * 删除单个学生\n\t * @param id\n\t * @return\n\t */\n\tint removeUser(Long id);\n\n\t/**\n\t * 更新学生信息\n\t * @param user\n\t * @return\n\t */\n\tUser updateUser(User user);\n\n\t/**\n\t * 根据id获取学生信息\n\t * @param id\n\t * @return\n\t */\n\tUser getUserById(Long id);\n\n\t/**\n\t * 获取学生列表\n\t * @return\n\t */\n\tList<User> listUsers();\n}\n"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/serviceImpl/UserServiceImpl.java",
    "content": "package com.abel.example.serviceImpl;\n\nimport com.abel.example.bean.User;\nimport com.abel.example.dao.UserJpaDao;\nimport com.abel.example.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * @author abel\n * @ClassName UserServiceImpl\n * @date 2016年11月10日\n */\n@Service\npublic class UserServiceImpl implements UserService {\n    @Autowired\n    private UserJpaDao userJpaDao;\n\n    /**\n     * @param username\n     * @return\n     */\n    @Override\n    public User getUserByUserName(String username) {\n        return userJpaDao.getByUsernameIs(username);\n    }\n\n    @Override\n    public List<User> getByUsernameContaining(String username) {\n        return userJpaDao.findByUsernameContaining(username);\n    }\n\n    @Override\n    public User saveUser(User user) {\n        return userJpaDao.save(user);\n    }\n\n    @Override\n    public int removeUser(Long id) {\n       try {\n           userJpaDao.delete(id);\n       }catch (Exception e) {\n           return 0;\n       }\n        return 1;\n    }\n\n    @Override\n    public User updateUser(User user) {\n        return userJpaDao.save(user);\n    }\n\n    @Override\n    public User getUserById(Long id) {\n        return  userJpaDao.findOne(id);\n    }\n\n    @Override\n    public List<User> listUsers() {\n        return userJpaDao.findAll();\n    }\n}\n"
  },
  {
    "path": "springboot-swagger-ui/src/main/java/com/abel/example/util/CommonUtil.java",
    "content": "package com.abel.example.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang3.StringUtils;\n\npublic  class CommonUtil {\n\n    /**\n     * 从request中获得参数Map，并返回可读的Map.\n     *\n     * @param request the request\n     * @return the parameter map\n     */\n    public static Map<String, Object> getParameterMap(HttpServletRequest request) {\n        // 参数Map\n        Map<String, String[]> properties = request.getParameterMap();\n        //返回值Map\n        Map<String, Object> returnMap = new HashMap<String, Object>();\n        Set<String> keySet = properties.keySet();\n        for(String key: keySet){\n            String[] values = properties.get(key);\n            String value = \"\";\n            if(values != null && (values.length==1&&StringUtils.isNotBlank(values[0]))?true:false){\n                for(int i=0;i<values.length;i++){\n                    if(values[i] != null && !\"\".equals(values[i])){\n//\t\t\t\t\t\t\tvalue = new String(values[i].getBytes(\"ISO-8859-1\"),\"UTF-8\") + \",\";\n                        value += values[i] + \",\";\n                    }\n                }\n                if(value != null && !\"\".equals(value)){\n                    value = value.substring(0, value.length()-1);\n                }\n                if(key.equals(\"keywords\")){//关键字特殊查询字符转义\n                    value =  value.replace(\"_\", \"\\\\_\").replace(\"%\", \"\\\\%\");\n                }\n                returnMap.put(key, value);\n            }\n        }\n        return returnMap;\n    }\n\n}"
  },
  {
    "path": "springboot-swagger-ui/src/main/resources/application.properties",
    "content": "server.port=8099\r\n\r\nms.db.driverClassName=com.mysql.jdbc.Driver\r\nms.db.url=jdbc:mysql://localhost:3306/abeldb?sprepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true\r\nms.db.username=root\r\nms.db.password=admin\r\nms.db.maxActive=500"
  }
]